Tronquer les nombres flottants avec PHP
Quand un nombre à virgule doit être tronqué à un certain chiffre après la virgule flottante, il s'avère qu'il n'est pas facile à faire. Par exemple, si la troncature doit être fait pour le deuxième chiffre après le point, les chiffres devraient être
45.8976 => 45.89, 0.0185 => 0.01
( deuxième chiffre après le point n'est pas arrondi selon le troisième chiffre après la virgule ).
Des fonctions comme la tour (la), number_format(), sprintf() de l'arrondi du nombre et de l'imprimer
45.8976 => 45.90, 0.0185 => 0.02
J'ai rencontré deux solutions et je me demande si ils sont assez bon et lequel est le mieux pour être utilisé
1. function truncNumber( $number, $prec = 2 )
{
return bccomp( $number, 0, 10 ) == 0 ? $number : round( $number - pow( 0.1, bcadd( $prec, 1 ) ) * 5, $prec );
}
2. function truncNumber($number, $prec = 2 )
{
return sprintf( "%.".$prec."f", floor( $number*pow( 10, $prec ) )/pow( 10, $prec ) );
}
source d'informationauteur Dessislava Mitova | 2011-01-12
Vous devez vous connecter pour publier un commentaire.
sol
fait ce que vous demandez.Vous ne trouverez pas un plus directs de la fonction pour cela, puisque c'est une sorte de chose étrange à le demander. Normalement, vous aurez ronde mathématiquement correct. Par curiosité Quoi avez-vous besoin?
c'est ma solution:
Pourquoi PHP ne gère pas mathamatic formules de la façon dont nous nous attendons, par exemple
floor(10.04 * 100) = 1003
quand nous le savons tous, il devrait être1004
.Ce problème n'est pas seulement en PHP, mais peut être trouvé dans toutes les langues, en fonction de l'erreur relative dans la langue utilisée.
PHP utilise la norme IEEE 754 double précision format qui a une erreur relative d'environ 1.11 e-16. (ressources)
Le vrai problème est que la fonction floor jette la valeur float en int valeur, par exemple
(int)(10.04 * 100) = 1003
comme nous le voyons dans le plancher de la fonction précédente. (ressources)Donc, pour surmonter ce problème, nous pouvons lancer le flotteur à une chaîne, une chaîne peut représenter n'importe quelle valeur avec précision, puis le plancher de la fonction sera de voter pour la chaîne de type int avec précision.
À tronquer des nombres le "meilleur" est à utiliser (j'ai pris un certain nombre ici qui fonctionne pour mon exemple):
Espérons que cette aide est facile que pour d'autres réponses ici, mais il est facile que pour le cas, il fonctionne. Voici un cas où il ne fonctionne pas pour (démo):
La fonction number_format est difficile, vous pouvez résoudre votre problème de cette façon (à partir de php.net):
Pour empêcher l'arrondissement qui se produit lors de la prochaine chiffres après la dernière décimale est 5 (mentionné par plusieurs personnes ci-dessous):
Si cette question est vieille, je vais poster une autre réponse au cas où quelqu'un tombe sur ce problème, comme je l'ai fait. Une solution simple pour les nombres positifs est:
Je l'ai testé contre une chaîne à la solution avec 10 millions aléatoire fractions et ils sont toujours appariés. Il ne présente pas la question de précision que
floor
à base de solutions.À l'extension de zéro et négatifs est assez simple.
La
round()
fonction a un paramètre de précision ainsi que d'un troisième paramètre permettant de spécifier la méthode d'arrondi, mais vous avez raison, il ne fait pas de troncature.Ce que vous êtes à la recherche pour les
floor()
etceil()
fonctions. L'inconvénient, c'est qu'ils n'ont pas un paramètre de précision, de sorte que vous aurez à faire quelque chose comme ceci:J'en vois une autre méthode pour le faire:
Mais ce n'est pas mieux que les autres...
round
peut être remplacé parsprintf
trop.À ce faire avec précision pour les deux +ve et -cinq numéros, vous devez utiliser:
- le php
floor()
fonction pour +ve numéros- le php
ceil()
fonction pour cinq numérosla raison pour cela est que
floor()
toujours arrondit le nombre baspas vers zéro.ie
floor()
efficacement tours -cinq numéros vers une plus grande valeur absoluepar exemple
floor(1.5) = 1
toutfloor(-1.5) = 2
Donc pour la méthode tronquer l'aide de
multiply by power, round, then divide by power
:-
floor()
ne fonctionne que pour les nombres positifs-
ceil()
ne fonctionne que pour les nombres négatifsPour tester cela, copiez le code suivant dans l'éditeur de http://phpfiddle.org/lite (ou similaire):
La raison pour cela, c'est la représentation binaire des nombres à virgule flottante. La valeur donnée à partir de ci-dessus
10.04
a représenté en interne comme une puissance de la base 2.Le potentiel de l'exposant pour la virgule flottante partie est
ln(0,04)/ln(2) = -4,64...
. Cela montre déjà que10.04
ne peut pas être représenté exactement comme un nombre binaire. Nous finissons par avoir quelque chose comme10.04 ~ 2^3 + 2^1 + 2^-5 + 2^-7 + 2^-11 + ...
d'avoir un maximum de précision en virgule flottante de la partie.C'est la raison qui
10.04
est à l'intérieur en fait un peu moins et peut être représentée comme10.039...
.Pour contourner ce problème il y a deux possibilités - soit jouer directement avec les opérations de la chaîne ou de l'utilisation d'une précision arbitraire de la bibliothèque comme
BcMath
pour PHP.La sortie pour le code ci-dessus va générer (j'ai ajouté la séparation des retours à la ligne pour plus de lisibilité):
Je voudrais ajouter mon contribuer à cette réponse avec la fonction que j'utilise pour mes besoins, qui considère tronquer les positions à la fois pour les valeurs positives et négatives.
...Je pense que c'est simple et rapide à utiliser.