Skip to content
This repository was archived by the owner on Dec 27, 2023. It is now read-only.

Commit 38dc1f8

Browse files
committed
Float precision errors using number_format() #37
1 parent 0d06bb7 commit 38dc1f8

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

src/Decimal.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,24 @@ public static function fromFloat($fltValue, $scale = null, $removeZeros = false)
138138
);
139139
}
140140

141-
$scale = ($scale === null) ? 16 : $scale;
141+
$defaultScale = 16;
142+
143+
$strValue = (string) $fltValue;
144+
if (preg_match("/^ (?P<int> \d*) (?: \. (?P<dec> \d+) ) E (?P<sign>[\+\-]) (?P<exp>\d+) $/x", $strValue, $capture)) {
145+
if ($scale === null) {
146+
if ($capture['sign'] == '-') {
147+
$scale = $capture['exp'] + strlen($capture['dec']);
148+
} else {
149+
$scale = $defaultScale;
150+
}
151+
}
152+
$strValue = number_format($fltValue, $scale, '.', '');
153+
}
154+
155+
if ($scale === null) {
156+
$scale = $defaultScale;
157+
}
142158

143-
$strValue = number_format($fltValue, $scale, '.', '');
144159
if ($removeZeros) {
145160
$strValue = self::removeTrailingZeros($strValue, $scale);
146161
}

tests/Decimal/DecimalFromFloatTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,42 @@ public function testNoFloat()
3838
{
3939
Decimal::fromFloat(5);
4040
}
41+
42+
public function floatProvider()
43+
{
44+
$tests = [
45+
[1.1, "1.1"],
46+
[1234567890.0, "1234567890"],
47+
[1.1234567890, "1.123456789"],
48+
[-1.1234567890, "-1.123456789"],
49+
[0.000001, "0.0000010"],
50+
[0.000001, "0.000001", null, !!'removeZeroes'],
51+
[90.05, "90.05"],
52+
];
53+
54+
if (PHP_INT_SIZE) {
55+
// These tests probably won't work if you're not testing on x86-64.
56+
// It might also be better to mark the tests skipped. It is certainly
57+
// useful to cover this functionality off though as it hits the exponent
58+
// parsing in Decimal::fromFloat()
59+
$tests[] = [
60+
1230123074129038740129734907810923874017283094.1,
61+
"1230123074129038665578332283019326242900934656.0000000000000000"
62+
];
63+
$tests[] = [
64+
0.0000000000000000000000000000000000000000000000123412351234,
65+
"0.0000000000000000000000000000000000000000000000123412351234",
66+
];
67+
}
68+
return $tests;
69+
}
70+
71+
/**
72+
* @dataProvider floatProvider
73+
*/
74+
public function testFromFloat($in, $str, $scale=null, $removeZeroes=false)
75+
{
76+
$v = Decimal::fromFloat($in, $scale, $removeZeroes);
77+
$this->assertSame($str, $v->innerValue());
78+
}
4179
}

0 commit comments

Comments
 (0)