Skip to content

Commit 7b478ad

Browse files
committed
Too Many Digits
We can't handle more digits than Php allows. Neither can Excel. Just do our best without throwing an Error.
1 parent e39dfe3 commit 7b478ad

File tree

2 files changed

+38
-1
lines changed
  • src/PhpSpreadsheet/Calculation/MathTrig
  • tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig

2 files changed

+38
-1
lines changed

src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ class Trunc
1313
* TRUNC.
1414
*
1515
* Truncates value to the number of fractional digits by number_digits.
16+
* This will probably not be the precise result in the unlikely
17+
* event that the number of digits to the left of the decimal
18+
* plus the number of digits to the right exceeds PHP_FLOAT_DIG
19+
* (or possibly that value minus 1).
20+
* Excel is unlikely to do any better.
1621
*
1722
* @param array|float $value Or can be an array of values
1823
* @param array|int $digits Or can be an array of values
@@ -52,7 +57,7 @@ public static function evaluate(array|float|string|null $value = 0, array|int|st
5257
return ($minusSign === '') ? $result : -$result;
5358
}
5459
$decimals = PHP_FLOAT_DIG - strlen((string) (int) $value);
55-
$resultString = sprintf('%.' . $decimals . 'F', $value);
60+
$resultString = ($decimals < 0) ? sprintf('%F', $value) : sprintf('%.' . $decimals . 'F', $value);
5661
$regExp = '/([.]\\d{' . $digits . '})\\d+$/';
5762
$result = $minusSign . (preg_replace($regExp, '$1', $resultString) ?? $resultString);
5863

tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,36 @@ public static function providerTruncArray(): array
4747
'matrix' => [[[3.14, 3.141], [3.14159, 3.14159265]], '3.1415926536', '{2, 3; 5, 8}'],
4848
];
4949
}
50+
51+
public function testTooMuchPrecision(): void
52+
{
53+
// This test is pretty screwy. Possibly shouldn't even attempt it.
54+
// At any rate, these results seem to indicate that PHP
55+
// maximum precision is PHP_FLOAT_DIG - 1 digits, not PHP_FLOAT_DIG.
56+
// If that changes, at least one of these tests will have to change.
57+
$sheet = $this->getSheet();
58+
$sheet->getCell('E1')->setValue(10.0 ** (PHP_FLOAT_DIG - 3) + 1.2);
59+
$sheet->getCell('E2')->setValue('=TRUNC(E1,1)');
60+
$result = $sheet->getCell('E2')->getCalculatedValue();
61+
$expectedResult = '1' . str_repeat('0', PHP_FLOAT_DIG - 4) . '1.2';
62+
self::assertSame($expectedResult, (string) $result);
63+
64+
$sheet->getCell('F1')->setValue(10.0 ** (PHP_FLOAT_DIG - 2) + 1.2);
65+
$sheet->getCell('F2')->setValue('=TRUNC(F1,1)');
66+
$result = $sheet->getCell('F2')->getCalculatedValue();
67+
$expectedResult = '1' . str_repeat('0', PHP_FLOAT_DIG - 3) . '1';
68+
self::assertSame($expectedResult, (string) $result);
69+
70+
$sheet->getCell('G1')->setValue(10.0 ** (PHP_FLOAT_DIG - 1) + 1.2);
71+
$sheet->getCell('G2')->setValue('=TRUNC(G1,1)');
72+
$result = $sheet->getCell('G2')->getCalculatedValue();
73+
$expectedResult = '1.0E+' . (PHP_FLOAT_DIG - 1);
74+
self::assertSame($expectedResult, (string) $result);
75+
76+
$sheet->getCell('H1')->setValue(10.0 ** PHP_FLOAT_DIG + 1.2);
77+
$sheet->getCell('H2')->setValue('=TRUNC(H1,1)');
78+
$result = $sheet->getCell('H2')->getCalculatedValue();
79+
$expectedResult = '1.0E+' . PHP_FLOAT_DIG;
80+
self::assertSame($expectedResult, (string) $result);
81+
}
5082
}

0 commit comments

Comments
 (0)