php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #13550 intval() does not round off doubles correctly
Submitted: 2001-10-04 19:08 UTC Modified: 2001-10-05 17:06 UTC
From: mlemos at acm dot org Assigned:
Status: Not a bug Package: *Programming Data Structures
PHP Version: 4.0.6 OS: Linux 2.2.18
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mlemos at acm dot org
New email:
PHP Version: OS:

 

 [2001-10-04 19:08 UTC] mlemos at acm dot org
It seems that intval does not round off double numbers like the function that prints those numbers. Try this script to see the problem.

<?
	$decimal_places=2;
	$decimal_factor=pow(10.0,$decimal_places);
	$value='8.78';
	$double=doubleval($value);
	$scaled=$double*$decimal_factor;
	$integer=intval($scaled);
	$round=intval(round($scaled));
	var_dump($decimal_places,$decimal_factor,$value,$double,$scaled,$integer,$round);
?>

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-10-05 03:58 UTC] rasmus@php.net
Could you be a little less cryptic please?  I would expect this to print:
int 2
float 100
string '8.78'
float 8.78
float 878
int 878
int 878
Which is exactly what I am seeing.  $scaled = 8.78 * 100.0 which gives a double value of 878.00 therefore round(878.00) would be 878 and intval(878) is 878.  What exactly are you expecting to be different here?
 [2001-10-05 08:30 UTC] mlemos at acm dot org
Except that it doesn't, here and in many other users machines it prints:

int(2)
float(100)
string(4) "8.78"
float(8.78)
float(878)
int(877)
int(878)

glibc rpm version is 2.2-7.

 [2001-10-05 08:35 UTC] manuel@php.net
The bug is real. Try it on the mentioned OS with glibc version mentioned in the report to see it.
 [2001-10-05 15:56 UTC] jeroen@php.net
No, floating point numbers are ALWAYS inprecise, and you shouldn't trust on their exact values.

See the warning on http://www.php.net/manual/en/language.types.float.php

The problem is that $scaled is 877.99999999999999 or something, and because of the precision setting in php.ini it is printed as 878, but when using (int) cast, or intval(), it will be rounded down (or twowards zero, don't reacall).

By the way, pow(int,int) will yield integer values when possible since 4.0.7, which nukes one possible source of floating point problems (unless you use 10.0 of course, but that doesn't make sense in PHP)

BTW: this is a FAQ, will add an entry.
 [2001-10-05 16:40 UTC] manuel@php.net
I don't think you are understanding the problem.

Basically the bug is that in PHP:

intval($double)!=intval(round($double))

round($double) is still a floating point number.

The problem is that currently in PHP the intval() floating point rounding rule is not the same as round() rule.

This is a real PHP bug that needs to be fixed, because if:

echo $double;

prints the same as

echo round($double);

then

echo intval($double);

should print the same as

echo intval(round($double));

 [2001-10-05 16:45 UTC] jeroen@php.net
> Basically the bug is that in PHP:
> 
> intval($double)!=intval(round($double))

converting to integer will round DOWN, while rounding first rounds towards the nearst integer.

intval($float) and intval(floor($float)) should be the same for nonnegative $float's, but in the case of round that's not true.

So not a bug

 [2001-10-05 16:54 UTC] jeroen@php.net
<quote>
This is a real PHP bug that needs to be fixed, because if:

[1]echo $double;

prints the same as

[2]echo round($double);

then

[3]echo intval($double);

should print the same as

[4]echo intval(round($double));

</quote>

[1] and [2] _print_ the same, but they aren't. It's because of the precision setting in php.ini (14 significant numbers, IIRC)

This is inherently to floating point numbers. Simply don't trust them to the last digit.
 [2001-10-05 17:00 UTC] rasmus@php.net
Ok, you could have stated this to begin with:

intval($double)!=intval(round($double))

Where are you getting the idea that intval does a round()?

intval(3.99) would be 3
round(3.99) would be 4
Therefore intval(round(3.99)) would be 4
and thus often intval($double) != intval(round($double))
 [2001-10-05 17:06 UTC] jeroen@php.net
Manuel ment that 

intval($double)==intval(round($double))

should be true in the context of 

$double == round($double)


So his problem wasn't with mixing up round and intval, but his problem was that he didn't realize that

(string)$double == (string)round($double)

does not necessarily imply 

$double == round($double)

(and which is not the case in this case, because the difference being to small to show up in the string representation)

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 16:01:28 2024 UTC