Faustregel, wann std::pow am effizientesten ist?
-
Hallo allerseits! Habt ihr eine Faustregel, wann ihr std::pow (mit ganzzahligem, positivem Exponenten) aus Performancegründen entsprechenden Multiplikationen vorzieht? Beispiel:
double a = ... ; double d = a*a*a*a*a; // 5 Multiplikationen double d = std::pow(a, 5); // vs. std::pow
-
Ich hab keine Faustregel, so hohen Exponenten hab ich nie dass ich in diese Problemzone komme...
Allerdings gibts ja auch noch andere Ansätze, siehe auch
The most efficient way to implement an integer based power function pow(int, int).Außerdem kann es auch Fälle geben wo die Rundungsfehler nicht tolereriert werden können, deshalb wird es schwierig da eine allgemeine Aussage zu treffen.
-
Ausgemessen habe ich es noch nicht, aber ich würde sagen, die Zahl wird immer kleiner, weil die Fließkommaeinheiten auf dem Prozessor immer schneller werden, breiter, noch mehr Transitoren (warum nur eine Milliarde Transistoren, wenn auch zwei Milliarden gehen?), fettere Tabellenwerke, noch mehr parallel.
Bis ca 3 multipliziere ich per Hand und drüber kommt math::pow, aber nicht aus Performancegründen, sondern weil es so praktischer zu tippen ist. Code mit pow(double) war bei mir bisher nie performancekritisch. Und Polynome wollen eh das Hornerschema statt pow.
-
Moment mal. Wenn die Zahl der Multiplikationen zur Compile-Zeit feststeht... wisst ihr, wovon ich spreche?
-
Arcoth schrieb:
Moment mal. Wenn die Zahl der Multiplikationen zur Compile-Zeit feststeht... wisst ihr, wovon ich spreche?
Ja, boost::pow.
-
Vorschlag (aber nur für positive Exponenten):
namespace detail { template <typename T, unsigned N> struct pow { static T value(T x) { T s = pow<T, (N >> 1)>::value(x); // teile und herrsche! return s * s * (1 + (N & 1) * (x - 1)); // = s^2 * s, falls N ungerade, sonst s^2 } }; template <typename T> struct pow<T, 1> { static T value(T x) { return x; } }; template <typename T> struct pow<T, 0> { static T value(T x) { return x; } }; } template <unsigned N, typename T> T static_pow(T base) { return detail::pow<T, N>::value(base); } ... static_pow<6>(3.14159);
-
Hoppla, bei der Spezialisierung soll natürlich 1 und nicht x stehen.
-
Also der Spezialisierung von 0.
-
Arcoth schrieb:
Moment mal. Wenn die Zahl der Multiplikationen zur Compile-Zeit feststeht... wisst ihr, wovon ich spreche?
Kann ich davon ausgehen, dass der compiler ein "std::pow(d, i)", wobei "i" eine Compiletime Konstante ist, in die optimale Form übersetzt? Also gilt zB. das hier?
double d = a*a; // sind die beiden Ausdrücke gleichwertig, double d = std::pow(a, 2); // weil der Optimierer hier a*a raus macht?
Irgendwie kann ich nie einschätzen, wie klug der Compiler ist
-
Exponents schrieb:
Kann ich davon ausgehen, dass der compiler ein "std::pow(d, i)", wobei "i" eine Compiletime Konstante ist, in die optimale Form übersetzt? Also gilt zB. das hier?
double d = a*a; // sind die beiden Ausdrücke gleichwertig, double d = std::pow(a, 2); // weil der Optimierer hier a*a raus macht?
Kommt auf den Compiler drauf an:
Irgendwie kann ich nie einschätzen, wie klug der Compiler ist
Kommt auf den Compiler drauf an. GCC und Clang inlinen pow(a,2) zu a*a, aber pow(a,3) schon nicht mehr. Der icc inlined bis zu pow(a,200), aber pow(a,201) nicht mehr.
-
OhneBooooooost schrieb:
template <typename T> struct pow<T, 0> { static T value(T x) { return x; } };
Weil [c]x^0[/c] bekanntermaßen [c]x[/c] ist...x^0
ist nichtx
.
Außerdem fehlt daconstexpr
.EDIT: Oh, bin auch noch zu spät mit der 1.
-
TyRoXx schrieb:
Weil
x^0
bekanntermaßenx
ist...x^0=1
-
daddy_felix schrieb:
TyRoXx schrieb:
Weil
x^0
bekanntermaßenx
ist...x^0=1
Nein, x^0 = x XOR 0 = x
-
TyRoXx schrieb:
OhneBooooooost schrieb:
template <typename T> struct pow<T, 0> { static T value(T x) { return x; } };
Weil [c]x^0[/c] bekanntermaßen [c]x[/c] ist...x^0
ist nichtx
.
Außerdem fehlt daconstexpr
.EDIT: Oh, bin auch noch zu spät mit der 1.
Wo soll da ein constexpr hin? Die Basis ist ein Laufzeitwert.