On Wed, Mar 07, 2012 at 09:10:22PM +0900, AIDA Shinra wrote:
> At Tue, 6 Mar 2012 17:12:02 +0000,
> Stuart Henderson wrote:
> >
> > On 2012/03/07 01:00, AIDA Shinra wrote:
> > > Hi,
> > >
> > > I found the e() and l() in the bc(1) math library are not
> > > precise. Their scaling algorithms are wrong.
> > >
> > > In addition, BSD bc evaluates length(0.000) to 1 instead of 3.
> > > Such a behaviour will surprise people who expect that
> > > length(x) >= scale(x). While POSIX is silent, the GNU bc returns 3.
> > >
> > > The attached patches fix them. They also enable the editline in the
> > > intaractive "bc -d".
> > >
> > > See also:
> > > http://www.FreeBSD.org/cgi/query-pr.cgi?pr=bin/159227
> > >
> > > Regards,
> > > shinra
> > >
> > > [demime 1.01d removed an attachment of type application/octet-stream]
> > >
> > > [demime 1.01d removed an attachment of type application/octet-stream]
> > >
> >
> > Please send your diffs inline in the email body (diff -u format).
> > Thanks!
>
> Sorry, the patches follow:
Thanks for your diffs.
The editline and scale one are ok. The original dc(1) returns 0 for
length of anything equal to zero, which is obviously not correct. So
going with the gnu style behaviour is ok in this case.
I'll commit these two diffs soon, the lib one will take some more time
to verify.
-Otto
> Index: bc.library
> ===================================================================
> RCS file: /cvs/src/usr.bin/bc/bc.library,v
> retrieving revision 1.3
> diff -u -r1.3 bc.library
> --- bc.library 3 Feb 2007 21:15:06 -0000 1.3
> +++ bc.library 6 Mar 2012 14:20:40 -0000
> @@ -45,7 +45,9 @@
> r = ibase
> ibase = A
> t = scale
> - scale = t + .434*x + 1
> + scale = 0
> + if (x > 0) scale = (0.435*x)/1
> + scale = scale + t + 1
>
> w = 0
> if (x < 0) {
> @@ -94,26 +96,33 @@
> t = scale
>
> f = 1
> - scale = scale + scale(x) - length(x) + 1
> - s = scale
> + if (x < 1) {
> + s = scale(x)
> + } else {
> + s = length(x)-scale(x)
> + }
> + scale = 0
> + a = (2.31*s)/1 /* estimated integer part of the answer */
> + s = t + length(a) + 2 /* estimated length of the answer */
> while (x > 2) {
> - s = s + (length(x) - scale(x))/2 + 1
> - if (s > 0) scale = s
> + scale=0
> + scale = (length(x) + scale(x))/2 + 1
> + if (scale < s) scale = s
> x = sqrt(x)
> f = f*2
> }
> while (x < .5) {
> - s = s + (length(x) - scale(x))/2 + 1
> - if (s > 0) scale = s
> + scale = 0
> + scale = scale(x)/2 + 1
> + if (scale < s) scale = s
> x = sqrt(x)
> f = f*2
> }
>
> - scale = t + length(f) - scale(f) + 1
> + scale = t + length(f) + length(t + length(f)) + 1
> u = (x - 1)/(x + 1)
> -
> - scale = scale + 1.1*length(t) - 1.1*scale(t)
> s = u*u
> + scale = t + 2
> b = 2*f
> c = b
> d = 1
> Index: bc.y
> ===================================================================
> RCS file: /cvs/src/usr.bin/bc/bc.y,v
> retrieving revision 1.40
> diff -u -r1.40 bc.y
> --- bc.y 6 Oct 2011 14:37:56 -0000 1.40
> +++ bc.y 6 Mar 2012 14:20:40 -0000
> @@ -45,6 +45,7 @@
> #include <string.h>
> #include <termios.h>
> #include <unistd.h>
> +#include <stdlib.h>
>
> #include "extern.h"
> #include "pathnames.h"
> @@ -1144,19 +1145,6 @@
> dup(p[1]);
> close(p[0]);
> close(p[1]);
> - if (interactive) {
> - gettty(&ttysaved);
> - el = el_init("bc", stdin, stderr, stderr);
> - hist = history_init();
> - history(hist, &he, H_SETSIZE, 100);
> - el_set(el, EL_HIST, history, hist);
> - el_set(el, EL_EDITOR, "emacs");
> - el_set(el, EL_SIGNAL, 0);
> - el_set(el, EL_PROMPT, dummy_prompt);
> - el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
> - el_set(el, EL_BIND, "^D", "bc_eof", NULL);
> - el_source(el, NULL);
> - }
> } else {
> close(STDIN_FILENO);
> dup(p[0]);
> @@ -1165,6 +1153,19 @@
> execl(_PATH_DC, "dc", "-x", (char *)NULL);
> err(1, "cannot find dc");
> }
> + }
> + if (interactive) {
> + gettty(&ttysaved);
> + el = el_init("bc", stdin, stderr, stderr);
> + hist = history_init();
> + history(hist, &he, H_SETSIZE, 100);
> + el_set(el, EL_HIST, history, hist);
> + el_set(el, EL_EDITOR, "emacs");
> + el_set(el, EL_SIGNAL, 0);
> + el_set(el, EL_PROMPT, dummy_prompt);
> + el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
> + el_set(el, EL_BIND, "^D", "bc_eof", NULL);
> + el_source(el, NULL);
> }
> yywrap();
> return yyparse();
> Index: bcode.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/dc/bcode.c,v
> retrieving revision 1.41
> diff -u -r1.41 bcode.c
> --- bcode.c 15 May 2010 10:59:29 -0000 1.41
> +++ bcode.c 6 Mar 2012 14:25:38 -0000
> @@ -682,7 +682,7 @@
> u_int i;
>
> if (BN_is_zero(n->number))
> - return 1;
> + return n->scale ? n->scale : 1;
>
> int_part = new_number();
> fract_part = new_number();