aboutsummaryrefslogtreecommitdiff
path: root/src/parseTools.js
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-08-19 17:33:46 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-08-19 18:35:36 -0700
commit83972554f5fce6b2205d28211e115195dbdf6523 (patch)
tree758dd72852df8bf6000f91743b1abef521bedc0b /src/parseTools.js
parent50801f09f387731502e4f88358181f6300823360 (diff)
round doubles to i64s more carefully, especially small negatives; fixes #1539
Diffstat (limited to 'src/parseTools.js')
-rw-r--r--src/parseTools.js28
1 files changed, 25 insertions, 3 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 65e96264..046dac1b 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -727,15 +727,37 @@ function makeI64(low, high) {
// Splits a number (an integer in a double, possibly > 32 bits) into an USE_TYPED_ARRAYS == 2 i64 value.
// Will suffer from rounding. mergeI64 does the opposite.
function splitI64(value, floatConversion) {
- // We need to min here, since our input might be a double, and large values are rounded, so they can
+ // general idea:
+ //
+ // $1$0 = ~~$d >>> 0;
+ // $1$1 = Math_abs($d) >= 1 ? (
+ // $d > 0 ? Math.min(Math_floor(($d)/ 4294967296.0), 4294967295.0)
+ // : Math_ceil(Math.min(-4294967296.0, $d - $1$0)/ 4294967296.0)
+ // ) : 0;
+ //
+ // We need to min on positive values here, since our input might be a double, and large values are rounded, so they can
// be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a
// HEAP32 or |0'd, etc.
+ //
+ // For negatives, we need to ensure a -1 if the value is overall negative, even if not significant negative component
+
var lowInput = legalizedI64s ? value : 'VALUE';
if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput);
+ var low = lowInput + '>>>0';
+ var high = makeInlineCalculation(
+ asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
+ '(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' +
+ asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' +
+ ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' +
+ ')' +
+ ' : 0',
+ value,
+ 'tempDouble'
+ );
if (legalizedI64s) {
- return [lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0'];
+ return [low, high];
} else {
- return makeInlineCalculation(makeI64(lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0'), value, 'tempBigIntP');
+ return makeI64(low, high);
}
}
function mergeI64(value, unsigned) {