From: Nelson H. F. B. <be...@ma...> - 2008-08-28 22:37:38
|
I finally tracked down a problem that has bothered me for some time. It can be exhibited by a one-line test in ANY current version of gnuplot (4.3.2 or earlier): gnuplot> print log10(1.0e-162) ^ undefined value This slightly larger argument works: gnuplot> print log10(1.0e-161) -161.002592673726 On impact of this bug is that it is impossible to graph a function result over a logarithmic representation of the entire floating-point range with, e.g., plot "foo.dat" using (log10(abs($1))):($2) The fix is, fortunately, easy: diff -c -r gnuplot-4.2.3/src/eval.c gnuplot-4.2.3.1/src/eval.c *** gnuplot-4.2.3/src/eval.c Wed Mar 28 16:23:10 2007 --- gnuplot-4.2.3.1/src/eval.c Thu Aug 28 09:27:44 2008 *************** *** 323,332 **** --- 323,337 ---- case INTGR: return ((double) abs(val->v.int_val)); case CMPLX: + #if 0 return (sqrt(val->v.cmplx_val.real * val->v.cmplx_val.real + val->v.cmplx_val.imag * val->v.cmplx_val.imag)); + #else + return (hypot(val->v.cmplx_val.real, + val->v.cmplx_val.imag)); + #endif default: int_error(NO_CARET, "unknown type in magnitude()"); } The correct way to compute a Euclidean norm is NOT sqrt(x*x + y*y), but hypot(x,y). The first slashes the floating-point range in half because of premature overflow or underflow, but the second is valid for all possible argument pairs. As the diff line suggests, I made further changes in the configure.in file's AC_INIT() line to change the version locally from 4.2.3 to 4.2.3.1. However, versioning is the developers' job, so 4.2.3.1 is unique to my systems. I scanned for other instances of incorrect use of sqrt() instead of correct hypot(), but did not fix them. Many of them SHOULD be changed too, but I leave that job to the developers for the next official release of gnuplot: % find . -name '*.[ch]' | xargs grep -n 'sqrt.*[*]' ./src/fit.c:345: *lambda = sqrt(*lambda / num_data / num_params); ./src/os2/gclient.c:3833: ds = sqrt(dx*dx + dy*dy); ./src/os2/gclient.c:3874: ds = sqrt(dx*dx + dy*dy); ./src/datafile.c:2778: C1 = sqrt(x*x + y*y + z*z); ./src/datafile.c:2779: C2 = sqrt(x*x + y*y); ./src/eval.c:327: return (sqrt(val->v.cmplx_val.real * ./src/term.c:1165: double len_arrow = sqrt(dx * dx + dy * dy); ./src/specfun.c:347: /* log( sqrt( 2*pi ) ) */ ./src/specfun.c:377: /* log( sqrt( 2*pi ) ) */ ./src/specfun.c:408: /* log( sqrt( 2*pi ) ) */ ./src/specfun.c:440: /* log( sqrt( 2*pi ) ) */ ./src/specfun.c:1039: * z = sqrt( -2.0 * log(y) ); then the approximation is ./src/specfun.c:1043: * w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). ./src/specfun.c:1070:/* sqrt(2pi) */ ./src/specfun.c:1401: x = sqrt(-2.0 * log(y)); ./src/specfun.c:1859: x = x - (erf(x) - y) / (2.0 / sqrt(PI) * gp_exp(-x * x)); ./src/specfun.c:1860: x = x - (erf(x) - y) / (2.0 / sqrt(PI) * gp_exp(-x * x)); ./src/specfun.c:1861: x = x - (erf(x) - y) / (2.0 / sqrt(PI) * gp_exp(-x * x)); ./src/specfun.c:1890: p = sqrt(2.0 * (exp(1.0) * x + 1.0)); ./src/matrix.c:156: w = fsign(C[j][j]) * sqrt(C[j][j] * C[j][j] + C[i][j] * C[i][j]); ./src/matrix.c:210: gamma = sqrt(1 - sigma * sigma); ./src/matrix.c:213: sigma = fsign(rho) * sqrt(1 - gamma * gamma); ./src/standard.h:73:void f_sqrt __PROTO((union argument *x)); ./src/hidden3d.c:631: s = sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); ./src/hidden3d.c:656: s = sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); ./src/pm3d.c:100: /* pow(x, 0.25) is slightly faster than sqrt(sqrt(x)) */ ./src/standard.c:585: push(Gcomplex(&a, 0.0, -log(-y + sqrt(y * y + 1)) / ang2rad)); ./src/standard.c:587: beta = sqrt((x + 1) * (x + 1) + y * y) / 2 - sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:590: alpha = sqrt((x + 1) * (x + 1) + y * y) / 2 + sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:591: push(Gcomplex(&a, asin(beta) / ang2rad, -log(alpha + sqrt(alpha * alpha - 1)) / ang2rad)); ./src/standard.c:609: double alpha = sqrt((x + 1) * (x + 1) + y * y) / 2 ./src/standard.c:610: + sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:611: double beta = sqrt((x + 1) * (x + 1) + y * y) / 2 ./src/standard.c:612: - sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:618: log(alpha + sqrt(alpha * alpha - 1)) / ang2rad)); ./src/standard.c:749: push(Gcomplex(&a, log(y + sqrt(y * y + 1)) / ang2rad, 0.0)); ./src/standard.c:751: beta = sqrt((x + 1) * (x + 1) + y * y) / 2 - sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:752: alpha = sqrt((x + 1) * (x + 1) + y * y) / 2 + sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:753: push(Gcomplex(&a, log(alpha + sqrt(alpha * alpha - 1)) / ang2rad, -asin(beta) / ang2rad)); ./src/standard.c:770: push(Gcomplex(&a, log(x + sqrt(x * x - 1)) / ang2rad, 0.0)); ./src/standard.c:772: alpha = sqrt((x + 1) * (x + 1) + y * y) / 2 ./src/standard.c:773: + sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:774: beta = sqrt((x + 1) * (x + 1) + y * y) / 2 ./src/standard.c:775: - sqrt((x - 1) * (x - 1) + y * y) / 2; ./src/standard.c:776: push(Gcomplex(&a, log(alpha + sqrt(alpha * alpha - 1)) / ang2rad, ./src/standard.c:868:f_sqrt(union argument *arg) ./src/standard.c:882: /* -pi < ang < pi, so real(sqrt(z)) >= 0 */ ./src/standard.c:1072: return (sqrt(TWO_ON_PI / x) * ./src/standard.c:1085: return (sqrt(TWO_ON_PI / x) * ./src/standard.c:1168: w = sqrt(TWO_ON_PI / x) * ./src/standard.c:1185: return (sqrt(TWO_ON_PI / x) * ./src/mouse.c:586: rho = sqrt((x - rx) * (x - rx) + (y - ry) * (y - ry)); /* distance */ ./src/mouse.c:1522: int dist = sqrt((double)(dist_x * dist_x + dist_y * dist_y)); ./src/graphics.c:3239: x1 = xlowM + bar_size * tic / sqrt(1.0 + slope * slope); ./src/graphics.c:3240: x2 = xlowM - bar_size * tic / sqrt(1.0 + slope * slope); ./src/graphics.c:3248: x1 = xhighM + bar_size * tic / sqrt(1.0 + slope * slope); ./src/graphics.c:3249: x2 = xhighM - bar_size * tic / sqrt(1.0 + slope * slope); ./src/plot3d.c:403: K[i][j] = K[j][i] = -splines_kernel(sqrt(dx * dx + dy * dy)); ./src/plot3d.c:453: z = z - b[k] * splines_kernel(sqrt(dx * dx + dy * dy)); ------------------------------------------------------------------------------- - Nelson H. F. Beebe Tel: +1 801 581 5254 - - University of Utah FAX: +1 801 581 4148 - - Department of Mathematics, 110 LCB Internet e-mail: be...@ma... - - 155 S 1400 E RM 233 be...@ac... be...@co... - - Salt Lake City, UT 84112-0090, USA URL: http://www.math.utah.edu/~beebe/ - ------------------------------------------------------------------------------- |