Außerdem ist es nicht um einen seltsamen Bruchteil falsch – es ist genau um einen falsch!
Wenn dies an mir liegt, stoße ich an die Grenzen dessen, was pow() kann für mich tun, gibt es eine Alternative, die dies berechnen kann? Ich brauche eine Funktion, die rechnen kann x^ywo x^y ist immer kleiner als ULLONG_MAX.
Fun Fact: Diese Schleife endet nicht: for (float f = 0; f < INT_MAX; f++) { }
– ntoskrnl
30. Januar 2014 um 12:59 Uhr
Das l in %lf tut nichts. Sie drucken doubles, und ob Ihre Kompilierungsplattformen zuordnen double zum Double-Precision-Format von IEEE 754, werden Sie niemals drucken 9904578032905937.0 auf diese Weise, da es keine solche Zahl mit doppelter Genauigkeit gibt.
– Pascal Cuoq
30. Januar 2014 um 14:36 Uhr
@ntoskrnl: könnte nicht beenden. Es tat auf Crays und Systemen wo int war 16 Bit.
– MSalter
30. Januar 2014 um 15:07 Uhr
Mit einer double, können Sie sich immer auf die ersten 15 Dezimalstellen (signifikante Stellen) verlassen. Mit 17**12, das sind alle Ziffern bis zum Punkt. Mit 17**13, Sie können der letzten Ziffer nicht vertrauen. Dass double würde normalerweise (ohne Formatierung) geschrieben werden als 9.90457803290594E+15. Und 17**14 mit dieser Notation ist 1.68377826559401E+17.
– Jeppe Stig Nielsen
30. Januar 2014 um 16:25 Uhr
pow arbeitet mit double Zahlen. Diese stellen Zahlen der Form s * 2^e dar, wobei s eine 53-Bit-Ganzzahl ist. Deswegen double kann alle ganzen Zahlen unter 2^53 speichern, aber nur etwas Ganzzahlen über 2^53. Insbesondere kann es nur gerade Zahlen > 2^53 darstellen, da für e > 0 der Wert immer ein Vielfaches von 2 ist.
17^13 benötigt 54 Bits zur genauen Darstellung, also wird e auf 1 gesetzt und somit wird der berechnete Wert zu einer geraden Zahl. Der korrekte Wert ist ungerade, daher ist es nicht verwunderlich, dass er um eins abweicht. Ebenso benötigt 17^14 58 Bits zur Darstellung. Dass es auch um eins geht, ist ein glücklicher Zufall (solange man nicht zu viel Zahlentheorie anwendet), es ist einfach zufällig eins gegen a Vielfaches von 32das ist die Granularität, bei der double Zahlen dieser Größenordnung werden gerundet.
Für eine exakte ganzzahlige Potenzierung sollten Sie durchgehend ganze Zahlen verwenden. Schreibe dein Eigenes double-freie Potenzierungsroutine. Verwenden Sie die Potenzierung durch Quadrieren von if y kann groß sein, aber ich nehme an, es ist immer weniger als 64, was dieses Problem strittig macht.
@ Trideceth12 Das ist der offensichtliche Weg, den Sie tun sollten. Und es ist zu einfach, das Rad neu zu erfinden. Da Sie auf den Bereich einer 64-Bit-Ganzzahl und beschränkt sind x und y ganze Zahlen sind, gibt es weder Genauigkeitsprobleme zu lösen noch große Leistungsherausforderungen, die ausgeklügelte Algorithmen erfordern (10, 20 oder sogar 60 Multiplikationen sind billig, billiger als zum Beispiel jede I/O).
– Benutzer395760
30. Januar 2014 um 9:58 Uhr
Ein bisschen modulare Arithmetik: 17 % 16 = 1, also 17^n % 16 = 1 (was bedeutet, dass die vier niederwertigsten Bits in der binären Darstellung von 17^n immer 0001 sein werden).
– tom
30. Januar 2014 um 10:10 Uhr
@tom Das habe ich gemeint, indem ich zu viel Zahlentheorie +1 angewendet habe. Dies ist jedoch keine vollständige Erklärung, da es 1 (im Gegensatz zu 17) Modulo 32 sein muss, um um eins ausgeschaltet zu sein. Es gibt jedoch wahrscheinlich kein großes Muster, 17 ^ 15 ist mehr als eins.
– Benutzer395760
30. Januar 2014 um 10:22 Uhr
@delnan Ich habe 17 ^ 14 mit fünf abgeschnittenen Bits verpasst. Aber 17^2 % 32 = 1, also 17^14 % 32 = (17^2)^7 % 32 = 1.
– tom
30. Januar 2014 um 10:40 Uhr
@ trideceth12 Es gibt den Square-and-Multiply-Algorithmus, der im Exponenten eine logarithmische statt einer linearen Laufzeit hat.
– CodesInChaos
30. Januar 2014 um 16:00 Uhr
M Öhm
Die Zahlen, die Sie erhalten, sind zu groß, um mit a dargestellt zu werden double genau. Eine Gleitkommazahl mit doppelter Genauigkeit hat im Wesentlichen 53 signifikante Binärziffern und kann alle ganzen Zahlen bis darstellen 2^53 oder 9.007.199.254.740.992.
Bei höheren Zahlen werden die letzten Ziffern abgeschnitten und das Ergebnis Ihrer Berechnung wird auf die nächste Zahl gerundet, die als a dargestellt werden kann double. Zum 17^13, die nur geringfügig über der Grenze liegt, ist dies die nächste gerade Zahl. Für Zahlen größer als 2^54 dies ist die nächste Zahl, die durch vier teilbar ist, und so weiter.
Ahh .. die nächste gerade Zahl macht Sinn
– jsj
30. Januar 2014 um 9:47 Uhr
barak manos
Wenn Ihre Eingabeargumente nicht negative Ganzzahlen sind, können Sie Ihre eigenen implementieren pow.
Rekursiv:
unsigned long long pow(unsigned long long x,unsigned int y)
{
if (y == 0)
return 1;
if (y == 1)
return x;
return pow(x,y/2)*pow(x,y-y/2);
}
Iterativ:
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y--)
res *= x;
return res;
}
Effizient:
unsigned long long pow(unsigned long long x,unsigned int y)
{
unsigned long long res = 1;
while (y > 0)
{
if (y & 1)
res *= x;
y >>= 1;
x *= x;
}
return res;
}
Die rekursive Version ist nutzlos, da sie die Antwort nicht wiederverwendet. Ein rekursiver Aufruf genügt: root = y ? pow(x, y / 2) : 1; return root * root * (y&1 ? x : 1);
– tom
30. Januar 2014 um 10:32 Uhr
@chux: Habe gerade bemerkt, dass das fehlt if (y == 1)… Ich kann nicht glauben, dass es schon so lange da ist, ohne dass ich es merke. Danke vielmals!!!!! 🙂
– barak manos
26. August 2014 um 17:19 Uhr
@tom Recht hast du. Verpasste die “eventuell multipliziert mit pow (0, 1)”.
– chux – Wiedereinsetzung von Monica
6. September 2014 um 14:39 Uhr
Konstrukteur
Eine kleine Ergänzung zu anderen guten Antworten: Unter x86-Architektur ist es normalerweise verfügbar x87 80-Bit erweitertes Formatdas von den meisten C-Compilern über die unterstützt wird long double Typ. Dieses Format erlaubt den Betrieb mit ganzen Zahlen bis zu 2^64 ohne Lücken.
Es gibt ein Analogon von pow() in <math.h> die für den Betrieb vorgesehen ist long double Zahlen – powl(). Es sollte auch beachtet werden, dass der Formatbezeichner für die long double Werte ist anders als für double Einsen – %Lf. Also das richtige Programm mit der long double Typ sieht so aus:
Vielleicht musst du es wissen Was jeder Informatiker über Gleitkommaarithmetik wissen sollte?
– Irgendein Programmierer-Typ
30. Januar 2014 um 9:43 Uhr
Fun Fact: Diese Schleife endet nicht:
for (float f = 0; f < INT_MAX; f++) { }
– ntoskrnl
30. Januar 2014 um 12:59 Uhr
Das
l
in%lf
tut nichts. Sie druckendouble
s, und ob Ihre Kompilierungsplattformen zuordnendouble
zum Double-Precision-Format von IEEE 754, werden Sie niemals drucken9904578032905937.0
auf diese Weise, da es keine solche Zahl mit doppelter Genauigkeit gibt.– Pascal Cuoq
30. Januar 2014 um 14:36 Uhr
@ntoskrnl: könnte nicht beenden. Es tat auf Crays und Systemen wo
int
war 16 Bit.– MSalter
30. Januar 2014 um 15:07 Uhr
Mit einer
double
, können Sie sich immer auf die ersten 15 Dezimalstellen (signifikante Stellen) verlassen. Mit17**12
, das sind alle Ziffern bis zum Punkt. Mit17**13
, Sie können der letzten Ziffer nicht vertrauen. Dassdouble
würde normalerweise (ohne Formatierung) geschrieben werden als9.90457803290594E+15
. Und17**14
mit dieser Notation ist1.68377826559401E+17
.– Jeppe Stig Nielsen
30. Januar 2014 um 16:25 Uhr