From 70918b621854bb78bddd0392961be402bf07e187 Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Wed, 30 Nov 2022 17:55:35 +0000 Subject: [PATCH] fix: number to int conversions (#474) Fix toInt32, toUint32 conversions which caused test failures on arm64 by leveraging the power of go casts to simplify the conversion from float64 to integer types. --- value_number.go | 108 ++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 67 deletions(-) diff --git a/value_number.go b/value_number.go index 1c1d2c2e..e2a169cf 100644 --- a/value_number.go +++ b/value_number.go @@ -214,91 +214,65 @@ func (value Value) number() (number _number) { // ECMA 262: 9.5 func toInt32(value Value) int32 { - { - switch value := value.value.(type) { - case int8: - return int32(value) - case int16: - return int32(value) - case int32: - return value - } + switch value := value.value.(type) { + case int8: + return int32(value) + case int16: + return int32(value) + case int32: + return value } + floatValue := value.float64() - if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { + if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 { return 0 } - if floatValue == 0 { // This will work for +0 & -0 - return 0 - } - remainder := math.Mod(floatValue, float_2_32) - if remainder > 0 { - remainder = math.Floor(remainder) - } else { - remainder = math.Ceil(remainder) + float_2_32 - } - if remainder > float_2_31 { - return int32(remainder - float_2_32) - } - return int32(remainder) + + // Convert to int64 before int32 to force correct wrapping. + return int32(int64(floatValue)) } func toUint32(value Value) uint32 { - { - switch value := value.value.(type) { - case int8: - return uint32(value) - case int16: - return uint32(value) - case uint8: - return uint32(value) - case uint16: - return uint32(value) - case uint32: - return value - } + switch value := value.value.(type) { + case int8: + return uint32(value) + case int16: + return uint32(value) + case uint8: + return uint32(value) + case uint16: + return uint32(value) + case uint32: + return value } + floatValue := value.float64() - if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { + if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 { return 0 } - if floatValue == 0 { - return 0 - } - remainder := math.Mod(floatValue, float_2_32) - if remainder > 0 { - remainder = math.Floor(remainder) - } else { - remainder = math.Ceil(remainder) + float_2_32 - } - return uint32(remainder) + + // Convert to int64 before uint32 to force correct wrapping. + return uint32(int64(floatValue)) } +// ECMA 262 - 6.0 - 7.1.8. func toUint16(value Value) uint16 { - { - switch value := value.value.(type) { - case int8: - return uint16(value) - case uint8: - return uint16(value) - case uint16: - return value - } + switch value := value.value.(type) { + case int8: + return uint16(value) + case uint8: + return uint16(value) + case uint16: + return value } + floatValue := value.float64() - if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { + if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 { return 0 } - if floatValue == 0 { - return 0 - } - remainder := math.Mod(floatValue, float_2_16) - if remainder > 0 { - remainder = math.Floor(remainder) - } else { - remainder = math.Ceil(remainder) + float_2_16 - } - return uint16(remainder) + + // Convert to int64 before uint16 to force correct wrapping. + return uint16(int64(floatValue)) } // toIntSign returns sign of a number converted to -1, 0 ,1