From 3a2fd0b5db98fea60a1d0c380b74038d45ee7b85 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 24 Oct 2008 12:50:59 -0400 Subject: [PATCH] Improve floating point scaling in UnitConverter. When precision dictates that a number be zero padded, we cannot give sprintf() a negative precision specifier. This commit implements manual negative precision printing of floats, taking into account common rounding errors with floating point numbers. Signed-off-by: Edward Z. Yang --- NEWS | 2 ++ library/HTMLPurifier/UnitConverter.php | 12 ++++++++++++ tests/HTMLPurifier/UnitConverterTest.php | 4 ++++ tests/index.php | 23 ++++++++++++++++++++--- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 64a0d64e..0272724c 100644 --- a/NEWS +++ b/NEWS @@ -66,6 +66,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier throw an exception when MaintainLineNumbers is true, but a non-tracksLineNumbers is being used. - Detect if domxml extension is loaded, and use DirectLEx accordingly. +- Improve handling of big numbers with floating point arithmetic in UnitConverter. + Reported by David Morton. . Strategy_MakeWellFormed now operates in-place, saving memory and allowing for more interesting filter-backtracking . New HTMLPurifier_Injector->rewind() functionality, allows injectors to rewind diff --git a/library/HTMLPurifier/UnitConverter.php b/library/HTMLPurifier/UnitConverter.php index 6e304610..d69a132b 100644 --- a/library/HTMLPurifier/UnitConverter.php +++ b/library/HTMLPurifier/UnitConverter.php @@ -234,6 +234,18 @@ class HTMLPurifier_UnitConverter * Scales a float to $scale digits right of decimal point, like BCMath. */ private function scale($r, $scale) { + if ($scale < 0) { + // The f sprintf type doesn't support negative numbers, so we + // need to cludge things manually. First get the string. + $r = sprintf('%.0f', (float) $r); + // Due to floating point precision loss, $r will more than likely + // look something like 4652999999999.9234. We grab one more digit + // than we need to precise from $r and then use that to round + // appropriately. + $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1); + // Now we return it, truncating the zero that was rounded off. + return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); + } return sprintf('%.' . $scale . 'f', (float) $r); } diff --git a/tests/HTMLPurifier/UnitConverterTest.php b/tests/HTMLPurifier/UnitConverterTest.php index 09b69b72..6e92de4d 100644 --- a/tests/HTMLPurifier/UnitConverterTest.php +++ b/tests/HTMLPurifier/UnitConverterTest.php @@ -94,6 +94,10 @@ class HTMLPurifier_UnitConverterTest extends HTMLPurifier_Harness $this->assertConversion('11.112pt', '0.15433in'); } + function __onlytestRoundingBigNumber() { + $this->assertConversion('444400000000000000000000in', '42660000000000000000000000px'); + } + protected function assertSigFig($n, $sigfigs) { $converter = new HTMLPurifier_UnitConverter(); $result = $converter->getSigFigs($n); diff --git a/tests/index.php b/tests/index.php index ad043ee3..c706ffb5 100755 --- a/tests/index.php +++ b/tests/index.php @@ -36,9 +36,10 @@ $AC = array(); // parameters $AC['flush'] = false; $AC['standalone'] = false; $AC['file'] = ''; -$AC['xml'] = false; -$AC['dry'] = false; -$AC['php'] = $php; +$AC['xml'] = false; +$AC['dry'] = false; +$AC['php'] = $php; +$AC['help'] = false; $AC['type'] = ''; $AC['disable-phpt'] = false; @@ -46,12 +47,28 @@ $AC['only-phpt'] = false; // alias for --type=phpt $aliases = array( 'f' => 'file', + 'h' => 'help' ); // It's important that this does not call the autoloader. Not a problem // with a function, but could be if we put this in a class. htmlpurifier_parse_args($AC, $aliases); +if ($AC['help']) { +?>HTML Purifier test suite +Allowed options: + --flush + --standalone + --file (-f) HTMLPurifier/NameOfTest.php + --xml + --dry + --php /path/to/php + --type ( htmlpurifier | configdoc | fstools | htmlt | vtest | phpt ) + --disable-phpt +