[cfe-dev] [libcxx/test] Puzzling floating point behaviour
Edward Meewis
ed at extraordinarymachine.nl
Fri Dec 9 07:58:40 PST 2011
Hi all,
When running the libcxx I got asserts in complex.transcendentals. After
a lot of digging I have the following:
-- pow_complex_test.cpp:
#include <complex>
#include <cmath>
#include <cstdio>
int main()
{
const std::complex<long double> a = std::complex<long double>(2, 3);
const std::complex<long double> b = std::complex<long double>(2, 0);
std::complex<long double> x = std::complex<long double>(-5, 12);
std::complex<long double> c = pow(a, b);
printf("c = pow(a,b) = %.20Le + i*%.20Le\n", real(c), imag(c));
printf("x = %.20Le + i*%.20Le\n\n", real(x), imag(x));
printf("err = c - x = %.20Le + i*%.20Le\n\n", real(c-x), imag(c-x));
long double r_a = sqrt(real(a)*real(a) + imag(a)*imag(a));
long double th_a = atan(imag(a)/real(a));
/* bw = b*log(a) = 2*log(r_a) + i*2*th_a */
std::complex<long double> bw = b*log(a);
/* d = exp(x) = exp(xr) * (cos(xi) + i*sin(xi) */
std::complex<long double> d = exp(b*log(a));
std::complex<long double> dx0 = exp(std::complex<long
double>(bw.real(), bw.imag()));
std::complex<long double> dx1 =
std::complex<long double>(exp(bw.real()) * cos(bw.imag()),
exp(bw.real()) * sin(bw.imag()));
std::complex<long double> dx2 =
(long double)exp(bw.real()) *
std::complex<long double>(cos(bw.imag()), sin(bw.imag()));
printf("d = exp(b*log(a)) = %.20Le + i*%.20Le\n", real(d), imag(d));
printf("dx0 = %.20Le + i*%.20Le\n", real(dx0), imag(dx0));
printf("dx1 = %.20Le + i*%.20Le\n", real(dx1), imag(dx1));
printf("dx2 = %.20Le + i*%.20Le\n\n", real(dx2), imag(dx2));
printf("err = d - x = %.20Le + i*%.20Le\n", real(d-x), imag(d-x));
printf("err = dx0 - x = %.20Le + i*%.20Le\n", real(dx0-x),
imag(dx0-x));
printf("err = dx1 - x = %.20Le + i*%.20Le\n", real(dx1-x),
imag(dx1-x));
printf("err = dx2 - x = %.20Le + i*%.20Le\n", real(dx2-x),
imag(dx2-x));
}
--
clang -std=c++0x -nostdinc++ -I/home/emeewis/contrib/libcxx/include
-nodefaultlibs -L/home/emeewis/contrib/libcxx/lib -lc++
-L/usr/home/emeewis/contrib/FreeBSD-HEAD/lib/libcxxrt -lcxxrt -lm
pow_complex_test.cpp && ./a.out
c = pow(a,b) = -4.99999999981561327189e+00 + i*1.19999999999030784181e+01
x = -5.00000000000000000000e+00 + i*1.20000000000000000000e+01
err = c - x = 1.84386728108165698359e-10 + i*-9.69215818713564658538e-11
d = exp(b*log(a)) = -4.99999999981561327189e+00 +
i*1.19999999999030784181e+01
dx0 = -4.99999999981561327189e+00 + i*1.19999999999030784181e+01
dx1 = -5.00000000000000000000e+00 + i*1.20000000000000000000e+01
dx2 = -5.00000000000000000000e+00 + i*1.20000000000000000000e+01
err = d - x = 1.84386728108165698359e-10 + i*-9.69215818713564658538e-11
err = dx0 - x = 1.84386728108165698359e-10 + i*-9.69215818713564658538e-11
err = dx1 - x = 0.00000000000000000000e+00 + i*0.00000000000000000000e+00
err = dx2 - x = 0.00000000000000000000e+00 + i*0.00000000000000000000e+00
So, calculating c = pow(a,b) ever more directly eventually getting the
correct result.
Compiling against libstdc++ gets correct results.
I'm guessing long doubles get demoted somewhere. Does anyone have an
idea what the problem may be?
Regards, Edward
More information about the cfe-dev
mailing list