2011-04-11 12 views
62

Al buscar en Efficient way to compute p^q (exponentiation), where q is an integer y revisar los estándares de C++ 98 y C++ 11 noté que aparentemente la sobrecarga std::pow(double, int) se eliminó en C++ 11.¿Por qué se eliminó std :: pow (double, int) de C++ 11?

En C++ 98 26.5/6 tiene la firma double pow(double, int);.

en C++ 11 26,8 todo lo que pude encontrar fue sobrecargas teniendo un par de float, double, o long double, y una nota explícita que en caso de una mezcla de tipos de parámetros integrales & doble, que la sobrecarga pow(double, double) debe ser escogido.

¿Es esto solo una aclaración de la intención anterior, se agregaron incorrectamente en C++ 98, se eliminaron realmente en C++ 11 o algo más?

Obviamente, la versión pow(double, int) ofrece una buena oportunidad para la optimización, por lo que parece extraño que se eliminen. ¿Un compilador seguiría cumpliendo los estándares para proporcionar una sobrecarga tan optimizada?

+0

¿Qué hay de C++ 03? –

+2

La buena oportunidad para la optimización es para la implementación de bignum, no para "doble" que probablemente sea compatible con hardware y donde también se pueda usar una solución log + mul + exp. – 6502

+2

@Ben Voigt: C++ 03 coincide con C++ 98 en esto. –

Respuesta

81
double pow(double, int); 

no se ha eliminado de la especificación. Simplemente ha sido reformulado. Ahora vive en [c.math]/p11. Cómo se calcula es un detalle de implementación. La única C++ 03 firma que ha cambiado es:

float pow(float, int); 

Esto devuelve ahora doble:

double pow(float, int); 

Y este cambio fue hecho para la compatibilidad C.

Aclaración:

26,8 [cmath]/p11 dice:

Por otra parte, habrá adicional sobrecargas suficientes para asegurar:

  1. Si algún argumento que corresponde a un parámetro doble tiene tipo double double, y luego todos los argumentos correspondientes aLos parámetros doblesse emiten efectivamente a doble largo.

  2. lo contrario, si cualquier argumento correspondiente a un parámetro de doble ha tipo tipo de doble o un número entero, entonces todos los argumentos correspondientes a parámetros dobles son efectivamente fundido al doble.

  3. De lo contrario, todos los argumentos que corresponden a los parámetros dobles son efectivamente emitidos para flotar.

Este párrafo implica toda una serie de sobrecargas, incluyendo:

double pow(double, int); 
double pow(double, unsigned); 
double pow(double, unsigned long long); 

etc.

Pueden ser sobrecargas reales o pueden implementarse con plantillas restringidas. Lo he implementado personalmente en ambos sentidos y estoy a favor de la implementación de plantillas restringidas.

Segunda actualización que soluciona los problemas de optimización:

Se permite que la aplicación para optimizar cualquier sobrecarga. Pero recuerde que una optimización debe ser solo eso. La versión optimizada debería devolver la misma respuesta. La experiencia de los implementadores de funciones como pow es que cuando se toma la molestia de asegurarse de que su implementación tomando un exponente integral da la misma respuesta que la implementación que toma un exponente de punto flotante, la "optimización" suele ser más lenta.

Como una demostración de los siguientes programa imprime a cabo pow(.1, 20) dos veces, una vez usando std :: prisionero de guerra, y la segunda vez usando un algoritmo "optimizado" aprovechando el exponente integral:

#include <cmath> 
#include <iostream> 
#include <iomanip> 

int main() 
{ 
    std::cout << std::setprecision(17) << std::pow(.1, 20) << '\n'; 
    double x = .1; 
    double x2 = x * x; 
    double x4 = x2 * x2; 
    double x8 = x4 * x4; 
    double x16 = x8 * x8; 
    double x20 = x16 * x4; 
    std::cout << x20 << '\n'; 
} 

En mi sistema esta imprime:

1.0000000000000011e-20 
1.0000000000000022e-20 

O en notación hexadecimal:

0x1.79ca10c92422bp-67 
0x1.79ca10c924232p-67 

Y sí, los implementadores de pow realmente se preocupan por todos esos bits en el extremo inferior.

Así que mientras la libertad está ahí para mezclar pow(double, int) con un algoritmo separado, la mayoría de los implementadores que conozco han renunciado a esa estrategia, con la posible excepción de buscar exponentes integrales muy pequeños. Y en ese caso, generalmente es ventajoso poner ese control en la implementación con el exponente de punto flotante para obtener el máximo rendimiento de su inversión de optimización.

+0

¿Es esto un cambio en la versión final aún no publicada? –

+0

No. Trataré de aclarar en mi respuesta ... –

+0

Usted dice, 'pow (double, int);' no ha sido eliminado, pero mi compilador parece pensar que sí, ¿cómo puedo acceder? – crobar

Cuestiones relacionadas