[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

regression in bc(1) -> bug in dc



Hi all,

I noticed a regression in bc(1) over the previous (GNU) version when
calculating the square root from integers :

$ uname -a
OpenBSD wormhole 3.4 GENERIC#18 i386
$ echo 'sqrt(10)' | bc
3

$ uname -a
OpenBSD banana 3.6 BANANA#0 i386
$ echo 'sqrt(10)' | bc
2

Since our bc is now dc-based, this proves to be a bug in dc(1) :

$ dc
10
v
p
2

Not all square roots display this behaviour, but initial testing shows
quite a few (small) integers affected :

$ cat sqrts
for i in `jot 1000`
do
	a=`echo "sqrt(${i})" | bc`
	b=`echo "sqrt(${i})" | bc -l | cut -f1 -d'.'`
	if [ ${a} -ne ${b} ] # this assumes bc -l is right
	then
		echo -n "${i} "
	fi
done
$ sh sqrts
9 10 11 40 41 42 43 44 49 50 51 52 53 54 55 208 209 210 211 212 213 \
214 215 216 217 218 219 220 225 226 227 228 229 230 231 232 233 234 \
235 236 237 238 239 928 929 930 931 932 933 934 935 936 937 938 939 \
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 \
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 \
978 979 980 981 982 983 984 985 986 987 988 989 990 991 

I've tried patching dc. Unfortunately, I couldn't really figure out
from the code if this was 'simply' some sort of off-by-one-bug or
a slight oversight. Therefor I have assumed the latter and patched
accordingly :

Index: bcode.c
===================================================================
RCS file: /cvs/src/usr.bin/dc/bcode.c,v
retrieving revision 1.22
diff -u -r1.22 bcode.c
--- bcode.c	11 Feb 2004 20:44:31 -0000	1.22
+++ bcode.c	30 Nov 2004 18:32:27 -0000
@@ -1255,7 +1255,7 @@
 {
 	struct number	*n;
 	struct number	*r;
-	BIGNUM		*x, *y;
+	BIGNUM		*x, *y, *z;
 	u_int		scale;
 	BN_CTX		*ctx;
 
@@ -1263,6 +1263,7 @@
 	if (n == NULL) {
 		return;
 	}
+	z = BN_dup(n->number);
 	if (BN_is_zero(n->number)) {
 		r = new_number();
 		push_number(r);
@@ -1285,6 +1286,15 @@
 			bn_check(BN_rshift1(x, x));
 			if (bsqrt_stop(x, y))
 				break;
+		}
+		if (n->scale == 0) {
+			BN_one(x);
+			bn_check(BN_add(x, x, y));
+			bn_check(BN_sqr(x, x, ctx));
+			if (BN_cmp(x, z) != 1) {
+				BN_one(x);
+				bn_check(BN_add(y, y, x));
+			}
 		}
 		r = bmalloc(sizeof(*r));
 		r->scale = scale;


This diff appears to solve the regression mentioned above :

$ sh sqrts
$ 

Any comments ?

Cheers,

Paul 'WEiRD' de Weerd

-- 
>++++++++[<++++++++++>-]<+++++++.>+++[<------>-]<.>+++[<+
+++++++++++>-]<.>++[<------------>-]<+.--------------.[-]
                 http://www.weirdnet.nl/