From 62022d588108c11fa57e23ba03536c2a5eae06c8 Mon Sep 17 00:00:00 2001 From: Ian Farmer Date: Mon, 9 Jul 2007 01:31:31 +0000 Subject: [PATCH] While loading chunks, check if double values can be represented as integers, and load them as LIntegers instead of LDoubles if so. Also change test2 so that it does not fail because of the rounding problem. With these changes, 4 out of 7 test cases in LuaJTest now pass. --- src/main/java/lua/io/LoadState.java | 25 ++++++- src/test/java/lua/io/LoadStateTest.java | 92 ++++++++++++++++++++++++ src/test/res/test2.lua | 2 +- src/test/res/test2.luac | Bin 3161 -> 3170 bytes 4 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/test/java/lua/io/LoadStateTest.java diff --git a/src/main/java/lua/io/LoadState.java b/src/main/java/lua/io/LoadState.java index 761e5007..b7cfb1fa 100644 --- a/src/main/java/lua/io/LoadState.java +++ b/src/main/java/lua/io/LoadState.java @@ -189,14 +189,33 @@ public class LoadState { return new LString( s ); } + static LNumber longBitsToLuaNumber( long bits ) { + if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) { + return new LInteger( 0 ); + } + + int e = (int)((bits >> 52) & 0x7ffL) - 1023; + + if ( e >= 0 && e < 31 ) { + long f = bits & 0xFFFFFFFFFFFFFL; + int shift = 52 - e; + long intPrecMask = ( 1L << shift ) - 1; + if ( ( f & intPrecMask ) == 0 ) { + int intValue = (int)( f >> shift ) | ( 1 << e ); + return new LInteger( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue ); + } + } + + double value = Double.longBitsToDouble(bits); + return new LDouble( value ); + } + LNumber loadNumber() throws IOException { if ( this.luacIsNumberIntegral ) { int value = loadInt(); return new LInteger( value ); } else { - long bits = loadInt64(); - double value = Double.longBitsToDouble(bits); - return new LDouble( value ); + return longBitsToLuaNumber( loadInt64() ); } } // diff --git a/src/test/java/lua/io/LoadStateTest.java b/src/test/java/lua/io/LoadStateTest.java new file mode 100644 index 00000000..546d3068 --- /dev/null +++ b/src/test/java/lua/io/LoadStateTest.java @@ -0,0 +1,92 @@ +package lua.io; + +import java.util.Random; + +import junit.framework.TestCase; +import lua.value.LDouble; +import lua.value.LInteger; +import lua.value.LNumber; + +public class LoadStateTest extends TestCase { + double[] DOUBLE_VALUES = { + 0.0, + 1.0, + 2.5, + 10.0, + 16.0, + 16.125, + -1.0, + 2.0, + -2.0, + -10.0, + -0.25, + -25, + Integer.MAX_VALUE, + Integer.MAX_VALUE - 1, + (double)Integer.MAX_VALUE + 1.0, + Integer.MIN_VALUE, + Integer.MIN_VALUE + 1, + (double)Integer.MIN_VALUE - 1.0, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.MAX_VALUE, + Double.MIN_NORMAL + }; + + public void testLongBitsToLuaNumber() { + for ( int i = 0; i < DOUBLE_VALUES.length; ++i ) { + double v = DOUBLE_VALUES[i]; + long bits = Double.doubleToLongBits( v ); + LNumber luaNumber = LoadState.longBitsToLuaNumber( bits ); + + assertEquals( v, luaNumber.luaAsDouble() ); + + if ( v != Integer.MIN_VALUE ) { + // Special case of MIN_VALUE is probably not worth dealing with. + // (Unlike zero, which is also a special case but much more common.) + assertEquals( "Value "+v+" (at index "+i+") can be represented as integer but was not", + luaNumber instanceof LInteger, v == (double)( (int) v ) ); + } + } + } + + private LNumber simpleBitsToLuaNumber( long bits ) { + double value = Double.longBitsToDouble( bits ); + int valueAsInt = (int) value; + + if ( value == (double) valueAsInt ) { + return new LInteger( valueAsInt ); + } else { + return new LDouble( value ); + } + } + + public void testLongBitsToLuaNumberSpeed() { + long[] BITS = new long[ 500000 ]; + Random r = new Random(); + + for ( int i = 0; i < DOUBLE_VALUES.length; ++i ) { + BITS[i] = Double.doubleToLongBits( DOUBLE_VALUES[i] ); + } + for ( int i = DOUBLE_VALUES.length; i < BITS.length; i += 2 ) { + BITS[i ] = r.nextLong(); + BITS[i+1] = Double.doubleToLongBits( r.nextDouble() ); + } + + long startTime = System.currentTimeMillis(); + for ( int j = 0; j < BITS.length; ++j ) { + LoadState.longBitsToLuaNumber( BITS[j] ); + } + long endTime = System.currentTimeMillis(); + long complexConversionTime = endTime - startTime; + + startTime = System.currentTimeMillis(); + for ( int j = 0; j < BITS.length; ++j ) { + simpleBitsToLuaNumber( BITS[j] ); + } + endTime = System.currentTimeMillis(); + long simpleConversionTime = endTime - startTime; + + assertTrue( complexConversionTime < simpleConversionTime ); + } +} diff --git a/src/test/res/test2.lua b/src/test/res/test2.lua index 6daf11b0..3993cbe2 100644 --- a/src/test/res/test2.lua +++ b/src/test/res/test2.lua @@ -11,7 +11,7 @@ function myfunc(x) return x*x; end -print( myfunc(0.1) ) +print( myfunc(0.25) ) do local oldMyfunc = myfunc diff --git a/src/test/res/test2.luac b/src/test/res/test2.luac index 0febd6a634e1c12e513498e8d13374cbbca6d773..231358478d4a5255fe9a090930d4adff350b32d3 100644 GIT binary patch delta 244 zcmaiuy$!-Z3`XBwau>k_5sE-UHw0ZSMGC|U*#)x#9h51kky6ne8_?1+2_{I03T#