xref: /titanic_44/usr/src/lib/libshell/common/tests/arith.sh (revision 1e4c938b57d1656808e4112127ff1dce3eba5314)
1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2010 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                  Common Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#            http://www.opensource.org/licenses/cpl1.0.txt             #
11#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	let Errors+=1
25}
26alias err_exit='err_exit $LINENO'
27
28Command=${0##*/}
29integer Errors=0
30
31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
32trap "cd /; rm -rf $tmp" EXIT
33
34trap '' FPE # NOTE: osf.alpha requires this (no ieee math)
35
36integer x=1 y=2 z=3
37if	(( 2+2 != 4 ))
38then	err_exit 2+2!=4
39fi
40if	((x+y!=z))
41then	err_exit x+y!=z
42fi
43if	(($x+$y!=$z))
44then	err_exit $x+$y!=$z
45fi
46if	(((x|y)!=z))
47then	err_exit "(x|y)!=z"
48fi
49if	((y >= z))
50then	err_exit "y>=z"
51fi
52if	((y+3 != z+2))
53then	err_exit "y+3!=z+2"
54fi
55if	((y<<2 != 1<<3))
56then	err_exit "y<<2!=1<<3"
57fi
58if	((133%10 != 3))
59then	err_exit "133%10!=3"
60	if	(( 2.5 != 2.5 ))
61	then	err_exit 2.5!=2.5
62	fi
63fi
64d=0
65((d || 1)) || err_exit 'd=0; ((d||1))'
66if	(( d++!=0))
67then	err_exit "d++!=0"
68fi
69if	(( --d!=0))
70then	err_exit "--d!=0"
71fi
72if	(( (d++,6)!=6 && d!=1))
73then	err_exit '(d++,6)!=6 && d!=1'
74fi
75d=0
76if	(( (1?2+1:3*4+d++)!=3 || d!=0))
77then	err_exit '(1?2+1:3*4+d++) !=3'
78fi
79for	((i=0; i < 20; i++))
80do	:
81done
82if	(( i != 20))
83then	err_exit 'for (( expr)) failed'
84fi
85for	((i=0; i < 20; i++)); do	: ; done
86if	(( i != 20))
87then	err_exit 'for (( expr));... failed'
88fi
89for	((i=0; i < 20; i++)) do	: ; done
90if	(( i != 20))
91then	err_exit 'for (( expr))... failed'
92fi
93if	(( (i?0:1) ))
94then	err_exit '(( (i?0:1) )) failed'
95fi
96if	(( (1 || 1 && 0) != 1 ))
97then	err_exit '( (1 || 1 && 0) != 1) failed'
98fi
99if	(( (_=1)+(_x=0)-_ ))
100then	err_exit '(_=1)+(_x=0)-_ failed'
101fi
102if	((  (3^6) != 5))
103then	err_exit '((3^6) != 5) failed'
104fi
105integer x=1
106if	(( (x=-x) != -1 ))
107then	err_exit '(x=-x) != -1 failed'
108fi
109i=2
110if	(( 1$(($i))3 != 123 ))
111then	err_exit ' 1$(($i))3 failed'
112fi
113((pi=4*atan(1.)))
114point=(
115	float x
116	float y
117)
118(( point.x = cos(pi/6), point.y = sin(pi/6) ))
119if	(( point.x*point.x + point.y*point.y > 1.01 ))
120then	err_exit 'cos*cos +sin*sin > 1.01'
121fi
122if	(( point.x*point.x + point.y*point.y < .99 ))
123then	err_exit 'cos*cos +sin*sin < .99'
124fi
125if [[ $((y=x=1.5)) != 1 ]]
126then	err_exit 'typecast not working in arithmetic evaluation'
127fi
128typeset -E x=1.5
129( ((x++))  ) 2>/dev/null
130if [[ $? == 0 ]]
131then	err_exit 'postincrement of floating point allowed'
132fi
133( ((++x))  ) 2>/dev/null
134if [[ $? == 0 ]]
135then	err_exit 'preincrement of floating point allowed'
136fi
137x=1.5
138( ((x%1.1))  ) 2>/dev/null
139if [[ $? == 0 ]]
140then	err_exit 'floating point allowed with % operator'
141fi
142x=.125
143if	[[ $(( 4 * x/2 )) != 0.25 ]]
144then	err_exit '(( 4 * x/2 )) is not 0.25, with x=.125'
145fi
146if	[[ $(( pow(2,3) )) != 8 ]]
147then	err_exit '$(( pow(2,3) )) != 8'
148fi
149( [[ $(( pow(2,(3)) )) == 8 ]] ) 2> /dev/null
150if	(( $? ))
151then	err_exit '$(( pow(2,(3)) )) != 8'
152fi
153unset x
154integer x=1; integer x=1
155if	[[ $x != 1 ]]
156then	err_exit 'two consecutive integer x=1 not working'
157fi
158unset z
159{ z=$(typeset -RZ2 z2; (( z2 = 8 )); print $z2) ;} 2>/dev/null
160if [[ $z != "08" ]]
161then	err_exit "typeset -RZ2 leading 0 decimal not working [z=$z]"
162fi
163{ z=$(typeset -RZ3 z3; (( z3 = 8 )); print $z3) ;} 2>/dev/null
164if [[ $z != "008" ]]
165then	err_exit "typeset -RZ3 leading 0 decimal not working [z=$z]"
166fi
167unset z
168typeset -Z3 z=010
169(( z=z+1))
170if	[[ $z != 011 ]]
171then	err_exit "leading 0's in -Z not treated as decimal"
172fi
173unset x
174integer x=0
175if	[[ $((x+=1)) != 1  ]] || ((x!=1))
176then	err_exit "+= not working"
177	x=1
178fi
179x=1
180if	[[ $((x*=5)) != 5  ]] || ((x!=5))
181then	err_exit "*= not working"
182	x=5
183fi
184if	[[ $((x%=4)) != 1  ]] || ((x!=1))
185then	err_exit "%= not working"
186	x=1
187fi
188if	[[ $((x|=6)) != 7  ]] || ((x!=7))
189then	err_exit "|= not working"
190	x=7
191fi
192if	[[ $((x&=5)) != 5  ]] || ((x!=5))
193then	err_exit "&= not working"
194	x=5
195fi
196function newscope
197{
198	float x=1.5
199	(( x += 1 ))
200	print -r -- $x
201}
202if	[[ $(newscope) != 2.5 ]]
203then	err_exit "arithmetic using wrong scope"
204fi
205unset x
206integer y[3]=9 y[4]=2 i=3
207(( x = y[3] + y[4] ))
208if	[[ $x != 11 ]]
209then	err_exit "constant index array arithmetic failure"
210fi
211(( x = $empty y[3] + y[4] ))
212if	[[ $x != 11 ]]
213then	err_exit "empty constant index array arithmetic failure"
214fi
215(( x = y[i] + y[i+1] ))
216if	[[ $x != 11 ]]
217then	err_exit "variable subscript index array arithmetic failure"
218fi
219integer a[5]=3 a[2]=4
220(( x = y[a[5]] + y[a[2]] ))
221if	[[ $x != 11 ]]
222then	err_exit "nested subscript index array arithmetic failure"
223fi
224unset y
225typeset -Ai y
226y[three]=9 y[four]=2
227three=four
228four=three
229(( x = y[three] + y[four] ))
230if	[[ $x != 11 ]]
231then	err_exit "constant associative array arithmetic failure"
232fi
233(( x = y[$three] + y[$four] ))
234if	[[ $x != 11 ]]
235then	err_exit "variable subscript associative array arithmetic failure"
236fi
237$SHELL -nc '((a = 1))' 2> /dev/null || err_exit "sh -n fails with arithmetic"
238$SHELL -nc '((a.b++))' 2> /dev/null || err_exit "sh -n fails with arithmetic2"
239unset z
240float z=7.5
241if	{ (( z%2 != 1));} 2> /dev/null
242then	err_exit '% not working on floating point'
243fi
244chr=(a ' ' '=' '\r' '\n' '\\' '\"' '$' "\\'" '[' ']' '(' ')' '<' '\xab' '\040' '`' '{' '}' '*' '\E')
245if	(('a' == 97))
246then	val=(97 32  61 13 10 92 34 36 39 91 93 40 41 60 171 32 96 123 125 42 27)
247else	val=(129 64 126 13 21 224 127 91 125 173 189 77 93 76 171 32 121 192 208 92 39 21)
248fi
249q=0
250for ((i=0; i < ${#chr[@]}; i++))
251do	if	(( '${chr[i]}' != ${val[i]} ))
252	then	err_exit "(( '${chr[i]}'  !=  ${val[i]} ))"
253	fi
254	if	[[ $(( '${chr[i]}' )) != ${val[i]} ]]
255	then	err_exit "(( '${chr[i]}' )) !=  ${val[i]}"
256	fi
257	if	[[ $(( L'${chr[i]}' )) != ${val[i]} ]]
258	then	err_exit "(( '${chr[i]}' )) !=  ${val[i]}"
259	fi
260	if	eval '((' "'${chr[i]}'" != ${val[i]} '))'
261	then	err_exit "eval (( '${chr[i]}'  !=  ${val[i]} ))"
262	fi
263	if	eval '((' "'${chr[i]}'" != ${val[i]} ' + $q ))'
264	then	err_exit "eval (( '${chr[i]}'  !=  ${val[i]} ))"
265	fi
266done
267unset x
268typeset -ui x=4294967293
269[[ $x != 4294967293 ]]  && err_exit "unsigned integers not working"
270x=32767
271x=x+1
272[[ $x != 32768 ]]  && err_exit "unsigned integer addition not working"
273unset x
274float x=99999999999999999999999999
275if	(( x < 1e20 ))
276then	err_exit 'large integer constants not working'
277fi
278unset x  y
279function foobar
280{
281	nameref x=$1
282	(( x +=1 ))
283	print $x
284}
285x=0 y=4
286if	[[ $(foobar y) != 5 ]]
287then	err_exit 'name references in arithmetic statements in functions broken'
288fi
289if	(( 2**3 != pow(2,3) ))
290then	err_exit '2**3 not working'
291fi
292if	(( 2**3*2 != pow(2,3)*2 ))
293then	err_exit '2**3*2 not working'
294fi
295if	(( 4**3**2 != pow(4,pow(3,2)) ))
296then	err_exit '4**3**2 not working'
297fi
298if	(( (4**3)**2 != pow(pow(4,3),2) ))
299then	err_exit '(4**3)**2 not working'
300fi
301typeset -Z3 x=11
302typeset -i x
303if	(( x != 11 ))
304then	err_exit '-Z3 not treated as decimal'
305fi
306unset x
307typeset -ui x=-1
308(( x >= 0 )) || err_exit 'unsigned integer not working'
309(( $x >= 0 )) || err_exit 'unsigned integer not working as $x'
310unset x
311typeset -ui42 x=50
312if	[[ $x != 42#18 ]]
313then	err_exit 'display of unsigned integers in non-decimal bases wrong'
314fi
315$SHELL -c 'i=0;(( ofiles[i] != -1 && (ofiles[i] < mins || mins == -1) ));exit 0' 2> /dev/null || err_exit 'lexical error with arithemtic expression'
316$SHELL -c '(( +1 == 1))' 2> /dev/null || err_exit 'unary + not working'
317typeset -E20 val=123.01234567890
318[[ $val == 123.0123456789 ]] || err_exit "rounding error val=$val"
319if	[[ $(print x$((10))=foo) != x10=foo ]]
320then	err_exit 'parsing error with x$((10))=foo'
321fi
322$SHELL -c 'typeset x$((10))=foo' 2> /dev/null || err_exit 'typeset x$((10)) parse error'
323unset x
324x=$(( exp(log(2.0)) ))
325(( x > 1.999 && x < 2.001 )) || err_exit 'composite functions not working'
326unset x y n
327typeset -Z8 x=0 y=0
328integer n
329for	(( n=0; n < 20; n++ ))
330do	let "x = $x+1"
331	(( y = $y+1 ))
332done
333(( x == n ))  || err_exit 'let with zero filled fields not working'
334(( y == n ))  || err_exit '((...)) with zero filled fields not working'
335typeset -RZ3 x=10
336[[ $(($x)) == 10 && $((1$x)) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros'
337unset y
338[[ $(let y=$x;print $y) == 10 && $(let y=1$x;print $y) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros with let'
339unset i ip ipx
340typeset -i hex=( 172 30 18 1)
341typeset -iu ip=0 ipx=0
342integer i
343for	((i=0; i < 4; i++))
344do	(( ip =  (ip<<8) | hex[i]))
345done
346for ((i=0; i < 4; i++))
347do	(( ipx = ip % 256 ))
348	(( ip /= 256 ))
349	(( ipx != hex[3-i] )) && err_exit "hex digit $((3-i)) not correct"
350done
351unset x
352x=010
353(( x == 8 )) || err_exit 'leading zeros not treated as octal arithmetic'
354(( $x == 8 )) || err_exit 'leading zeros not treated as octal arithmetic with $x'
355unset x
356typeset -Z x=010
357(( x == 10 )) || err_exit 'leading zeros not ignored for arithmetic'
358(( $x == 10 )) || err_exit 'leading zeros not ignored for arithmetic with $x'
359typeset -i i=x
360(( i == 10 )) || err_exit 'leading zeros not ignored for arithmetic assignment'
361(( ${x:0:1} == 0 )) || err_exit 'leading zero should not be stripped for x:a:b'
362c010=3
363(( c$x  == 3 )) || err_exit 'leading zero with variable should not be stripped'
364[[ $( ($SHELL -c '((++1))' 2>&1)2>/dev/null ) == *lvalue* ]] || err_exit "((++1)) not generating error message"
365i=2
366(( "22" == 22 )) || err_exit "double quoted constants fail"
367(( "2$i" == 22 )) || err_exit "double quoted variables fail"
368(( "18+$i+2" == 22 )) || err_exit "double quoted expressions fail"
369# 04-04-28 bug fix
370unset i; typeset -i i=01-2
371(( i == -1 )) || err_exit "01-2 is not -1"
372
373cat > $tmp/script <<-\!
374tests=$*
375typeset -A blop
376function blop.get
377{
378	.sh.value=777
379}
380function mkobj
381{
382	nameref obj=$1
383	obj=()
384	[[ $tests == *1* ]] && {
385		(( obj.foo = 1 ))
386		(( obj.bar = 2 ))
387		(( obj.baz = obj.foo + obj.bar ))	# ok
388		echo $obj
389	}
390	[[ $tests == *2* ]] && {
391		(( obj.faz = faz = obj.foo + obj.bar ))	# ok
392		echo $obj
393	}
394	[[ $tests == *3* ]] && {
395		# case 3, 'active' variable involved, w/ intermediate variable
396		(( obj.foz = foz = ${blop[1]} ))	# coredump
397		echo $obj
398	}
399	[[ $tests == *4* ]] && {
400		# case 4, 'active' variable, in two steps
401		(( foz = ${blop[1]} ))	# ok
402		(( obj.foz = foz ))		# ok
403		echo $obj
404	}
405	[[ $tests == *5* ]] && {
406		# case 5, 'active' variable involved, w/o intermediate variable
407		(( obj.fuz = ${blop[1]} ))	# coredump
408		echo $obj
409	}
410	[[ $tests == *6* ]] && {
411		echo $(( obj.baz = obj.foo + obj.bar ))	# coredump
412	}
413	[[ $tests == *7* ]] && {
414		echo $(( obj.foo + obj.bar ))	# coredump
415	}
416}
417mkobj bla
418!
419chmod +x $tmp/script
420[[ $($tmp/script 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
421[[ $($tmp/script 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
422[[ $($tmp/script 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
423[[ $($tmp/script 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
424[[ $($tmp/script 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
425[[ $($tmp/script 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
426[[ $($tmp/script 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed'
427unset foo
428typeset -F1 foo=123456789.19
429[[ $foo == 123456789.2 ]] || err_exit 'typeset -F1 not working correctly'
430
431# divide by zero
432
433for expr in '1/(1/2)' '8%(1/2)' '8%(1.0/2)'
434do	[[ $( ( $SHELL -c "( (($expr)) )  || print ok" ) 2>/dev/null ) == ok ]] || err_exit "divide by zero not trapped: $expr"
435done
436
437for expr in '1/(1.0/2)' '1/(1/2.0)'
438do	[[ $( ( $SHELL -c "( print -r -- \$(($expr)) )" ) 2>/dev/null ) == 2 ]] || err_exit "invalid value for: $expr"
439done
440[[ $((5||0)) == 1 ]] || err_exit '$((5||0))'" == $((5||0)) should be 1"
441$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7  && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working'
442$SHELL -c 'b=0; [[ $((b?a=1:b=9)) == 9 ]]' 2> /dev/null || err_exit 'b?a=1:b=9 not working'
443unset x
444(( x = 4*atan(1.0) ))
445[[ $x == "$((x))" ]] || err_exit  '$x !- $((x)) when x is pi'
446$SHELL -c  "[[  ${x//./} == {14,100}(\d) ]]" 2> /dev/null || err_exit 'pi has less than 14 significant places'
447if	(( Inf+1 == Inf ))
448then	set \
449		Inf		inf	\
450		-Inf		-inf	\
451		Nan		nan	\
452		-Nan		-nan	\
453		1.0/0.0		inf
454	while	(( $# >= 2 ))
455	do	x=$(printf "%g\n" $(($1)))
456		[[ $x == $2 ]] || err_exit "printf '%g\\n' \$(($1)) failed -- expected $2, got $x"
457		x=$(printf "%g\n" $1)
458		[[ $x == $2 ]] || err_exit "printf '%g\\n' $1 failed -- expected $2, got $x"
459		x=$(printf -- $(($1)))
460		[[ $x == $2 ]] || err_exit "print -- \$(($1)) failed -- expected $2, got $x"
461		shift 2
462	done
463	(( 1.0/0.0 == Inf )) || err_exit '1.0/0.0 != Inf'
464	[[ $(print -- $((0.0/0.0))) == ?(-)nan ]] || err_exit '0.0/0.0 != NaN'
465	(( Inf*Inf == Inf )) || err_exit 'Inf*Inf != Inf'
466	(( NaN != NaN )) || err_exit 'NaN == NaN'
467	(( -5*Inf == -Inf )) || err_exit '-5*Inf != -Inf'
468	[[ $(print -- $((sqrt(-1.0)))) == ?(-)nan ]]|| err_exit 'sqrt(-1.0) != NaN'
469	(( pow(1.0,Inf) == 1.0 )) || err_exit 'pow(1.0,Inf) != 1.0'
470	(( pow(Inf,0.0) == 1.0 )) || err_exit 'pow(Inf,0.0) != 1.0'
471	[[ $(print -- $((NaN/Inf))) == ?(-)nan ]] || err_exit 'NaN/Inf != NaN'
472	(( 4.0/Inf == 0.0 )) || err_exit '4.0/Inf != 0.0'
473else	err_exit 'Inf and NaN not working'
474fi
475unset x y n r
476n=14.555
477float x=$n y
478y=$(printf "%a" x)
479r=$y
480[[ $r == $n ]] || err_exit "output of printf %a not self preserving -- expected $x, got $y"
481unset x y r
482x=-0
483y=$(printf "%g %g %g %g %g %g\n" -0. -0 $((-0)) x $x $((x)))
484r="-0 -0 -0 -0 -0 -0"
485[[ $y == "$r" ]] || err_exit "-0 vs -0.0 inconsistency -- expected '$r', got '$y'"
486$SHELL -c '(( x=));:' 2> /dev/null && err_exit '((x=)) should be an error'
487$SHELL -c '(( x+=));:' 2> /dev/null && err_exit '((x+=)) should be an error'
488$SHELL -c '(( x=+));:' 2> /dev/null && err_exit '((x=+)) should be an error'
489$SHELL -c 'x=();x.arr[0]=(z=3); ((x.arr[0].z=2))' 2> /dev/null || err_exit '(((x.arr[0].z=2)) should not be an error'
490
491float t
492typeset a b r
493v="-0.0 0.0 +0.0 -1.0 1.0 +1.0"
494for a in $v
495do	for b in $v
496	do	(( r = copysign(a,b) ))
497		(( t = copysign(a,b) ))
498		[[ $r == $t ]] || err_exit $(printf "float t=copysign(%3.1f,%3.1f) => %3.1f -- expected %3.1f\n" a b t r)
499	done
500done
501
502typeset -l y y_ascii
503(( y=sin(90) ))
504y_ascii=$y
505(( y == y_ascii )) || err_exit "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" y_ascii)"
506
507( $SHELL  <<- \EOF
508	p=5
509	t[p]=6
510	while (( t[p] != 0 )) ; do
511		((
512		p+=1 ,
513		t[p]+=2 ,
514		p+=3 ,
515		t[p]+=5 ,
516		p+=1 ,
517		t[p]+=2 ,
518		p+=1 ,
519		t[p]+=1 ,
520		p-=6  ,
521		t[p]-=1
522		))
523	:
524	done
525EOF) 2> /dev/null ||  err_exit 'error with comma expression'
526
527N=(89551 89557)
528i=0 j=1
529[[ $(printf "%d" N[j]-N[i]) == 6 ]] || err_exit 'printf %d N[i]-N[j] failed'
530[[ $((N[j]-N[i])) == 6 ]] || err_exit  '$((N[j]-N[i])) incorrect'
531
532unset a x
533x=0
534((a[++x]++))
535(( x==1)) || err_exit '((a[++x]++)) should only increment x once'
536(( a[1]==1))  || err_exit 'a[1] not incremented'
537unset a
538x=0
539((a[x++]++))
540(( x==1)) || err_exit '((a[x++]++)) should only increment x once'
541(( a[0]==1))  || err_exit 'a[0] not incremented'
542unset a
543x=0
544((a[x+=2]+=1))
545(( x==2)) || err_exit '((a[x+=2]++)) should result in x==2'
546(( a[2]==1))  || err_exit 'a[0] not 1'
547
548unset a i
549typeset -a a
550i=1
551(( a[i]=1 ))
552(( a[0] == 0 )) || err_exit 'a[0] not 0'
553(( a[1] == 1 )) || err_exit 'a[1] not 1'
554
555unset a
556typeset -i a
557for ((i=0;i<1000;i++))
558do ((a[RANDOM%2]++))
559done
560(( (a[0]+a[1])==1000)) || err_exit '(a[0]+a[1])!=1000'
561
562exit $((Errors))
563