Pregunta

He notado un problema con la precisión de la larga versión doble de sqrt (). El siguiente código demuestra el problema.

#include <iostream>
#include <cmath>
#include <cfloat>

int main(int argc, char ** argv)
{
  int count=0;
  long double s=sqrt(3L);
  std::cout.precision(21);
  std::cout << "s=" << s << ", s^2=" << s*s << std::endl;
  while( s*s<3L+LDBL_EPSILON ) {
    s+=LDBL_EPSILON;
    std::cout << s << ' ' << s*s << std::endl;
    ++count;
  }
  std::cout << "sqrt(3L) is approximately " << count << " multiples of LDBL_EPSILON away from the correct value." << std::endl;
  return 0;
}

Compilando y ejecutando esto con

>g++ -o sqrt sqrt.cpp && ./sqrt

da

s=1.73205080756887719318, s^2=2.9999999999999996524
1.73205080756887719329 2.99999999999999965284
1.73205080756887719339 2.99999999999999965306
... (922 lines omitted)
1.73205080756887729347 2.99999999999999999978
1.73205080756887729357 3.00000000000000000022
sqrt(3L) is approximately 926 multiples of LDBL_EPSILON away from the correct value.

La versión doble regular de sqrt () da el doble más cercano al valor real.

La versión de G ++ que estoy usando es

>g++ -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.5 (Debian 4.4.5-8) 

¿Es esto un error conocido? ¿Debo informar esto en alguna parte?

¿Fue útil?

Solución

Tienes dos problemas aquí: primero, 3L promueve implícitamente a double no long double Entonces, aunque asigne el valor de retorno a un long double todavía está utilizando la versión de baja precisión de sqrt. Necesitarás static_cast 3 a long double como el argumento. En segundo lugar, solo el double versión de sqrt se importa al espacio de nombres global porque la sobrecarga de funciones no es compatible en C, debe usar std::sqrt en cambio.

De este modo:

long double s=std::sqrt(static_cast<long double>(3));

Otros consejos

¿El valor de la versión 'regular' de doble sqrt () está experimentando una mayor granularidad de redondeo que el doble largo? Esto es lo que esperaríamos. Podría ser que este redondeo 'granular' está golpeando cerca del valor correcto, más cerca que el doble SQRT largo.

La forma de verificar esto sería probar múltiples valores y comparar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top