Newsgroup: it.comp.www.php
Titolo: 0.715, numero maledetto per PHP?

Per favore, aiutatemi a togliermi un dubbio.
Provate ad eseguire questo semplicissimo codice:
<?php
$a = 0.715;
for($i = 0; $i < 1000; $i++){
    echo number_format($i + $a, 2, ',', '.') . '<br />';
}
?>
Dovrebbe stamparvi a video delle semplici somme.
Come vedrete, number_format dovrebbe arrotondare i decimali per
ECCESSO a .72, giusto?
Controllate anche per i numeri dal 256 al 326.
Io ho provato su server linux e win, e quando la parte intera è tra
256 e 326 l'arrotondamento avviene per DIFETTO, quindi mi ritrovo
256.71
257.71
etc...
Potete confermarmi che anche a voi viene questo risultato?
Io non ci capisco più niente, ho provato anche ausare le librerie bc,
gmp, ma niente, sembra che l'errore sia non nel calcolo ma appunto
nell'arrotondamento di number_format()..
Se invece a voi arrotonda tutto a 0.72, allora il problema è solo mio
(configurazione del php?)

 avviene per DIFETTO, quindi mi ritrovo
A me arrotonda tutto a .72 (Debian Linux x32, PHP 5.2.11)
Sembrerebbe un problema di approssimazione dei floating point, forse 
dipende dalle librerie matematiche che hai installato.
Bye.

 (configurazione del php?)
no a me da sempre .72....
PHP 5.2.8 (cli) (built: Dec 13 2008 18:38:00)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
Su Opensuse 11.1

 da 0 a 4 arrotonda per difetto, se va da 5 a 9 per eccesso.
Infatti, è quello che mi sarei aspettato anche io.
Solo che con il codice che vi ho postato a un certo punto qualcosa
sballa:
[.cut.]
251,72
252,72
253,72
254,72
255,72
256,71
257,71
258,71
259,71
260,71
261,71
[.cut.]
Ma i decimali sono sempre gli stessi, 0.715.
Provando con 0.716 funziona, ottengo sempre 0,72, idem con 0.714,
ottengo stabile 0,71.
Impazzisce con 0.715, e solo in quel range di numeri (256 - 326).
Testato su server win e linux (Apache/2.2.9 (Debian) PHP/
5.2.6-1+lenny3 with Suhosin-Patch mod_perl/2.0.4 Perl/v5.10.0)
C'è un qualche parametro del php.ini che potrebbe correggere questa
cosa, o mi consigliate di reinstallare le librerie (se si, quali?)

Alessandro Pellizzari ha scritto:

Stessa cosa su opensuse, e le considerazioni sono valide anche se a onor
del vero nella documentazione da nessuna parte è scritto che la funzione
arrotonda (poteva anche troncare al limite), comunque dagli esempi a
corredo della documentazione ufficiale si capisce.


wrote:

A me se arrotonda o tronca non importa più di tanto (anche se
preferirei l'arrotondamento classico, da 0 a 4 in difetto, da 5 a 9 in
eccesso), il mio problema e la cosa che mi fà in pazzire è che con
quella cifra in particolare (0.715, ho provato con altre combinazioni
e sembra che funzioni bene), nel range 256-326 fà in un modo piuttosto
che nell'altro.
Cioè, se troncasse sempre, va bene, basta saperlo e mi adatto, ma
perchè 292.715 arrotonda a 0,71 e 15.715 arrotonda a 0,72?

 cosa, o mi consigliate di reinstallare le librerie (se si, quali?)
precision
Io ce l'ho a 12 (il default).
Bye.

Alessandro Pellizzari ha scritto:

ci avevo pensato anche io e ho provato a modificarlo tramite
ini_set("precision","2");
ma non cambia nulla... l'ho messa sia a 6 che a 3 a 2...
comunque mi sembra impossibile che lui si trovi con un round non
deterministico che alle volte arrotonda il 0.5 per eccesso altre per
difetto.
micheg


Il mio valore di precision è 14.. inoltre nell'operazione che faccio
si parla del 3° decimale..
Anche su un server win con iis6 sà lo stesso problema... deve per
forza essere una qualche configurazione/libreria mancante.
Anche se non mi spiego perchè si verifica solo con 0.715....

 essere una qualche configurazione/libreria mancante.
Le versioni di PHP sono uguali?
Bye.


Windows Server 2003: PHP Version 5.1.6 - Windows NT SERVER 5.2 build
3790
Debian: PHP Version 5.2.6-1+lenny3 - Linux 2.6.24-etchnhalf.1-686 #1
SMP Wed Apr 29 18:45:14 UTC 2009 i686
Ho appena provato su un altro server (molto simile al secondo), stesso
problema.
Debian: PHP Version 5.2.0-8+etch13 - Linux  2.6.24-etchnhalf.1-amd64
#1 SMP Tue Dec 2 17:21:26 UTC 2008 x86_64

 (configurazione del php?)
Anche a me succede: easyphp 2.0.0.0 (Apache/2.2.3 (Win32) PHP/5.2.0)
-- 
Jax

Jax ha scritto:

Ho provato anche a cambiare qualche cifra a caso, ho notato per esempio 
che se metti 0,815, ti arrotonda strano SOLO a 4,81, se metti 0,915 SOLO 
a 8,91 e 9,91 :)
-- 
Jax

 Jax
Ma se ti arrotonda sempre per difetto potrebbe non essere un errore ma
una configurazione, nel mio caso mi arrotonda sempre per eccesso
tranne da 256 a 326... è quel 'tranne' che non riesco proprio a
spiegarmi -.-

 spiegarmi -.-
No, non hai capito... l'anomalia in cui arrotonda a x.x1 c'� anche con 
gli altri numeri, e solo nei casi che ti ho scritto... in tutti gli 
altri casi arrotonda a x.x2
-- 
Jax

 conversione decimale-binario.
Se la precisione fosse 16 bit, quel numero verrebbe convertito in
0.256713867187500 (arrivato ad una risoluzione di 1/32768 mi son stufato di
convertirli). Ma in realta' la risoluzione e' di 24 bit (se non 53, ma non
credo), per cui dovrebbe avvicinarsi molto maggiormente.
Magari PHP e' stato compilato con un compilatore che ha generato limiti di tipo
diversi.



Provato ieri sera anche un ubuntu 9.04, stesso problema.
Ho provato con altre combinazioni, il 'giochetto' si presenta con
praticamente tutti i numeri 0,X15 (tentando di arrotondare a due
decimali)..
Non sò bene se è un errore nella compilazione del php (però visto che
lo fà anche la macchina ubuntu non credo, su quella macchina
installammo pari pari la distribuzione di php5 'standard' di proposito
perchè ci serve come 'macchina da battaglia per i test'), non sò voi
ma io comincio a considerare number_format() inaffidabile, visto che
prima di usare questa funzione i numeri sembrano essere presi
correttamente.
$a = 45.715;
var_dump($a);
//float(45.715)
mi sono scritto la mia funzione per formattare le stringhe con
arrotondamento 'manuale' e bom, anche se è 3 volte pi lento del
normale number_format per ora non vedo soluzioni.
In futuro, pensavo una cosa: secondo voi, partendo dal presupposto che
il numero massimo con cui avrò a che fare sarà 999 miliardi con una
precisione di 6 decimali (per il calcolo di prezzi sono più che
sufficienti), potrebbe essere un'idea usare una base intera per i
calcoli e riformattarla con i decimali solo in fase di stampa
all'utente?
Cioè, l'utente inserisce 256.715, io lo trasformo in intero
moltiplicandolo per 1000000, = 256715000.
Tutti i miei calcoli li faccio usando 256715000, anche per quel che
riguarda lo storage nel database, lo 'riconverto' solo quando devo
mostrarlo all'utente, dividendolo per 1000000, mettendo la virgola al
posto del punto, etc.. (ma senza usare number_format, o siamo punto e
a capo)
Secondo voi può essere un idea fattibile (anche se sotto alcuni punti
di vista è un'oscenità?)

 all'utente?
E` quello che faccio sempre, soprattutto per i prezzi, che tanto hanno 
(quasi) sempre 2 sole cifre decimali. :)
Bye.


Ah ok ;)
Perchè fondamentalmente anche un numero > 999'999'999 viene
considerato float, ma spero che con i numeri interi non ci sia
problema di approssimazione.

 approssimazione.
Tecnicamente, qualsiasi numero >~2 miliardi viene convertito in float, 
perche` gli integer sono 32bit signed, mentre i float sono come i double 
in C, a 64bit.
Teoricamente, su macchine a 64bit dovresti essere tranquillo fino a 
qualche miliardo di miliardi anche con gli integer, ma penso dipenda da 
come viene compilato PHP.
Per essere veramente tranquillo, conviene usare le funzioni bc, se devi 
gestire numeri cosi` grossi. Perdi in prestazioni, ma almeno mantieni la 
precisione e non hai overflow.
Bye.