PHP array_sum ist 1 zu viel

te one

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.252
Hi,
hab ein Script entworfen dass zahlen(immer der doppelte wert der vorherigen zahl) in ein array speichert!

Nur ab ca. 60 mal verdoppeln, ist die gesamtsumme einfach um 1 zu hoch! woran liegt das?

Hier das script:
PHP:
$number = array();
$numberclean = array();
echo '<table border="1">';
//Beispielwert von 60
for ($x=1; $x<=60; $x++) {
  $pownumber = $x-1;
//wusste nicht, wie ichs am besten ohne rundung hinbekomm! so gehts aba ja auch
  $numberclean[$x] = number_format(pow ( 2, $pownumber ), 0, ",", "");
  $number[$x] = number_format(pow ( 2, $pownumber ), 0, ",", ".");
  echo '<tr><td>'.$number[$x].' </td><td> ('.$x.')</td></tr>';
  }
$allnumbers = number_format(array_sum($numberclean), 0, ",", ".");
echo '</table>';
echo '<br/>Alle Zahlen zusammen ergeben '.$allnumbers.'!<br/>';

print_r($numberclean);

print_r gibt mir das array aus, und alles stimmt!
allerdings gibt array_sum ab ca. 60 (habs in zehnerschritten probiert, 50 ging noch, 60 war da ergebnis eines zu viel) aus!

kann doch eigentlich nicht sein dass es einfach so 1 dazuzählt?!

mfg

ps:
print_r gibt folgendes aus:
Code:
Array ( [1] => 1 [2] => 2 [3] => 4 [4] => 8 [5] => 16 [6] => 32 [7] => 64 [8] => 128 [9] => 256 [10] => 512 [11] => 1024 [12] => 2048 [13]
 => 4096 [14] => 8192 [15] => 16384 [16] => 32768 [17] => 65536 [18] => 131072 [19] => 262144 [20] => 524288 [21] => 1048576 [22] 
=> 2097152 [23] => 4194304 [24] => 8388608 [25] => 16777216 [26] => 33554432 [27] => 67108864 [28] => 134217728 [29]
 => 268435456 [30] => 536870912 [31] => 1073741824 [32] => 2147483648 [33] => 4294967296 [34] => 8589934592 [35] =>
 17179869184 [36] => 34359738368 [37] => 68719476736 [38] => 137438953472 [39] => 274877906944 [40] => 549755813888 
[41] => 1099511627776 [42] => 2199023255552 [43] => 4398046511104 [44] => 8796093022208 [45] => 17592186044416 [46] =>
 35184372088832 [47] => 70368744177664 [48] => 140737488355328 [49] => 281474976710656 [50] => 562949953421312 [51] => 
1125899906842624 [52] => 2251799813685248 [53] => 4503599627370496 [54] => 9007199254740992 [55] => 18014398509481984 
[56] => 36028797018963968 [57] => 72057594037927936 [58] => 144115188075855872 [59] => 288230376151711744 [60] => 
576460752303423488 )
müsste also stimmen!
der gesamtwert ergibt aber komischerweiße 1.152.921.504.606.846.976
was gar nicht möglich ist, da alle zahlen bis auf die 1 gerade zahlen sind
-->ungerade zahl müsste das ergebnis sein!
Ergänzung ()

habs auch mit der formel: y=2*2^(x-1)
wobei x die anzahl der multiplikationsvorgänge(also halt von 1 hochgezählt) angibt
y ist hierbei gleich die gesamtanzahl

kommt dann auch 1 zu viel raus
 
Zuletzt bearbeitet:
Hü,

scheint an der Größe der Zahl zu liegen. Mit bcadd funktioniert es korrekt:
PHP:
foreach($numberclean as $number)
{
  $sum = bcadd($sum,$number);
}

echo $sum;
liefert
PHP:
1152921504606846975

Aber beachten, BC behandelt die Zahlen als Strings, das kann bremsen!
 
Zuletzt bearbeitet:
wow also liegts im grundgenommen gar net an meinem script!

aba ist i-wie schon komisch dass es dann eins mehr wird (noch dazu entstehen ja keine kommazahlen oda so, sondern nur ganze zahlen)
Ergänzung ()

*dumm guck*

oh man! der server den ich nutze unterstüzt kein bcadd()!
hat jemand ne andere möglichkeit??
Ergänzung ()

habs jetz mit normaler addition und foreach probiert! damit wirds leider mit zehnerpotenz gerundet!

PHP:
foreach($numberclean as $number)
{
  $sum = $sum + $number;
}

-->1.84467440737E+19

hätte es aber schon lieber genau
 
php hat als registergröße entweder 32-bit auf nem 32-bit betriebssystem oder sonst 64-bit. damit lassen sich maximal +2,147,483,647 bzw. +9,223,372,036,854,775,807 darstellen. alles was größer ist wird zu ner floating-point zahl konvertiert mit E+XX schreibweise.

du kannst also nur mit big integer befehlen arbeiten.
 
öhm bininteger sind java oder??

des OS ändert da was dran?(kann ich mir nicht vorstellen)

aber wenn ichs mit number_format mache, müsste es ja eigentlich auch gehen! kann doch nicht sein dass es mir da aus heiterem himmel einfach eines zu viel gibt!?
 
BigInteger ist Java und das Pendant dazu ist bcadd in PHP (BCMath-Library). Wenn du wirklich so große Zahlen brauchst kommst du um die Benutzung davon ned drum rum. Wie schon richtig gesagt wurde wandelt PHP automatisch von Integer nach float um wenn die Wertgrenze des Integer überschritten wird (im Gegensatz zu Java wo es halt überläuft). Nur ergeben sich da Rundungsfehler beim Rechnen mit so großen Zahlen und genau das passiert bei dir eben. Das Verhalten von PHP ist so gesehen schon praktisch nur etwas problematisch ist natürlich, dass der eigentliche Programmierfehler dadurch ned auffällt.

number_format bringt gar nichts weil die Rechnung eben mit floats nicht genau genug ist. Da hilft number_format 0,0.
 
zur erklärung float:
float hat eine feste anzahl an stellen, und es wird definiert an welche stelle das komma zu suchen ist. Wird die zahl zu groß, dann bekommt die zahl einfach ein mal 2^1 (2 hoch 1) dazu
beispiel:
angenommen float hat 3 ziffern zur verfügung. (im 10ner system)
wenn unsere zahl 1234 ist, dann wird daraus eine float zahl mit 123 mit einer potenz von 1 = 123 * 10^1 = 1234 -> die 4 fliegt weg.

alles im computer läuft aber im 2er system:
float mit 3 ziffern
1111 in float = 111 potenz 1 = 111 mit potenz 1 = 1110 als hätte man die 1 weggeschnitten.
Genau das passiert bei dir, da du ja immer verdoppelst...
0001 (1)
0010 (2)
0100 (4)
1000 (8)
------ +
1111 -> 1110 .. 1 zu wenig in der summe
Da es bei 60 Fehlschlägt, kann man wohl vermuten dass dein php auf einem 64 bit rechner läuft
wo die 4-5 fehlenden bits sind weiss ich nicht.. eins is schonmal wegen dem vorzeichen weg ;)
 
Er hat aber 1 zu viel ;)

Außerdem tritt der Fehler - wenn ich mich recht erinner - bei einer zur anderen Zahl auf, die gleich viele Stellen haben.
 
des OS ändert da was dran?(kann ich mir nicht vorstellen)

ist aber so :) -> http://www.php.net/integer

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.
 
float hat eine feste anzahl an stellen

das is übrigens ne falschmeldung :) float hat gar keine festen stellen, sondern ist die angabe eines bruches. was du meinst ist fixed-point.

float = S * (m * (2 ^ e)), S = -1 oder +1, m = 0..1, e = -128..127
m wird dabei angegeben als Summe von Brüchen.. z.B. 1/2 + 1/8 + 1/16 + ...
 
Zuletzt bearbeitet:
http://de.wikipedia.org/wiki/Gleitkommazahl
float ;)
0,1 (10) = 1/10
0,01 (10) = 1/100
0,001 (10) = 1/1000

0,1 (2) = 1/2
0,01 (2) = 1/4
0,001 (2) = 1/8
0,111 = 1/2 + 1/4 + 1/8

Nichts anderes hab ich doch erklärt?!
m hat dabei eine feste länge (anzahl an stellen).. .. zb 64 bit, was der genauigkeit der float zahl entspricht - womit wir bei dem beschriebenen Problem sind ;)
Die Zahl 0,001 (2) hat zb eine Stelle bzw eine gültige Ziffer
 
Zuletzt bearbeitet:
Also ich versteh ca. was ihr meint, aber:

Jedesmal wird die verdoppelte zahl in einer spalte ausgegeben!
Diese verdoppelten zahlen stimmen ja noch (also kann hier kein fehler drin sein)!

wenn ich dies jetzt mit number_format ausgebe, bekomm ich das ergebnis auch ohne potenzen, aber es ist eben 1 zu hoch!

und wegen euren rundungsfehlern (zB "macht sinn, da man in mathe ja bei 0,5 aufrundet"):
wo bekommt ihr ne kommazahl wenn ihr mit 1 anfangt und immer des ergebnis verdoppelt :lol:
also bei mir kommen nur ganze zahlen raus ;)

mit bcadd konnt ichs leider nicht machen, weil der server bcadd net kann :(
 
Der Fehler tritt ja erst dann auf wenn die zahl zu groß wird
gehen wir nochmal davon aus, dass man 3 Ziffern zur Verfügung hat:

0001 = 1,00 * 2^0
0010 = 1,00 * 2^1
0100 = 1,00 * 2^2
1000 = 1,00 * 2^3
All diese Zahlen sind problemlos mit float darstellebar, da sie nur eine Ziffer in der Mantisse brauchen um das Ergebnis exakt darzustellen. float kann alle zweierpotzenezn bis schätzungsweise 2^128 exakt darstellen. Das Problem ist, wenn die Zahl sehr genau ist.. also eine hohe Anzahl an gültigen Ziffern hat. Alle Zahlen bisher haben zwar 3 gültige Ziffern, aber wenn man sie nur mit einer gültigen Ziffer darstellen würde, würde man keinen Fehler machen, da die unbekannten Ziffern mit Nullen aufgefüllt werden (neutrale zahl bzgl der addition)

was passiert wenn wir addieren?
1111 = 1,11 * 2^3 mit überlauf 1 (letzte Zahl die nichtmehr dargestellt werden kann). Ist der Überlauf 1 -> aufrunden, ist er 0 -> abrunden.
1,11 * 2^3 + 1 * 2^0 = 10,00 * 2^3 = 1* 2^4 = 10000


Wie du siehst kommt natürlich ein "0,5" vor. Das ist alles nur eine Frage der darstellung.
Ich kann ja auch schreiben 0,5 = 5 * 10^-1 ... und schon hab ich ein Komma eliminiert..
andersrum (was man macht, weil man die Zahl nicht genau genug darstellen kann): 5 = 0,5 * 10
--> 5555 = 5,555 * 10^3
Mantisse mit maximal einer Ziffer:
16 = 1,6 * 10^1 -> 2 * 10^1 ... 16 ist durch 2 teilbar und wurde trotzdem aufgerundet weil ein "0,5" im der zweier Rechnung vorkommt..
Rechnen wir also nochmal im zweier System:
111,1 im zweier system = 4 + 2 + 1 + 1/2
da haste ein 0,5 ;)
 
also den post muss ich mir noch n paar mal durchlesen, vllt kapier ichs dann i-wann! :) :freak:

aber gibts denn jetz net einfach ne ganz simple lösung, wie des blöde ding genauer rechnet?
 
ok werd mal gucken ob ichs vllt i-wie dann mit bcadd machen kann!

naja "missbraucht" wird es nicht richtig! :D
diese berechnung brauch ich einfach nur für ein kleines rätsel für n paar bekannte von mir :p ,
damit die mal was zu tun habn *g*

und da ich eh meine php-kenntnisse verbessern möchte, hab ich mir gedacht, dass ich mir da halt schnell was schreibe (was sich ja jetzt doch als nicht so einfach entpuppt hat)!


dieses script war also mehr so zum spaß gedacht als irgendetwas supersinnvolles zu erledigen!
 
ich hab ma das script neugeschrieben und den unnötigen muell entfernt:
funzt perfekt. warum immer so viel text fuer nichts?

PHP:
echo '<table border="1">';

for ($x=0; $x<60; $x++) 
{
  $number[$x] = pow ( 2, $x );	
  	
  echo '<tr><td>'.$number[$x].' </td><td> ('.($x+1).')</td></tr>';
  $allnumbers = $allnumbers+$number[$x];
}

echo '</table>';
echo '<br/>Alle Zahlen zusammen ergeben '.$allnumbers.'<br/>';

zur berechnung von $allnumbers kannste aber auch ganz einfach, nach der for-schleife nochmal verdoppeln und dann eins abziehn ;)

$allnumbers = pow ( 2, 60 )-1;

mathe und coden scheint nich euer ding zu sein was xD
das ganze wird beim gluecksspiel (martingalissystem) eigentlich sehr oft genutzt xD hab mir da mal nen paar rechner fuer gebaut um roulette zu knacken xD

PHP:
$anzahl_multis = 60;

echo '<table border="1">';

for ($x=0; $x<$anzahl_multis; $x++) 
{
  $number[$x] = pow ( 2, $x );	  	
  echo '<tr><td>'.$number[$x].' </td><td> ('.($x+1).')</td></tr>'; 
}

$allnumbers = pow ( 2, $anzahl_multis )-1;

echo '</table>';
echo '<br/>Alle Zahlen zusammen ergeben '.$allnumbers.'<br/>';


ach ja klugscheißen muss ich leider auch nochmal ;) $allnumbers im antworttext mit einem ! zu verbinden is leider auch falsch weils dann fakultät dieser zahl wäre, und das is leider vollkommen falsch ...
 
Zuletzt bearbeitet:
gegenfrage: warum immer sinnlose antworten von leuten die meinen sie wissens besser?

dein script bringt auch einfach nur das ergebnis mit zehnerpotenz!

es geht aber darum dass ich die genaue zahl möchte!

außerdem wären trennzeichen zwischen den tausenderstellen immer ganz schön.
 
Ich deklariere ficken32 zu meinem persönlichen Held und häng mir ein Bild für seine übertriebene Intelligenz auf.

Wie löst du eigentlich das Problem der Formel eins? Anstatt 60 mal im Kreis zu fahren einfach stehn bleiben und n Bier trinken?
Was machst du wenns Benzin für eine Fahrt von München nach Berlin nicht reicht, und du kein Geld für mehr hast? Einfach in Stuttgart stehnbleiben und n Bier trinken?.. falls das Geld dafür noch reicht..
 
Zuletzt bearbeitet:

Ähnliche Themen

Zurück
Oben