@@ -1225,6 +1225,55 @@ function bit64.le_bytes_to_u64(str, offset)
12251225 return bit64 .new (high , low )
12261226end
12271227
1228+ ---- ----------------------------------------------------------------------------
1229+ -- Utility functions
1230+ ---- ----------------------------------------------------------------------------
1231+
1232+ --- Converts a {high, low} pair to a 16-character hexadecimal string.
1233+ --- @param value Int64HighLow The {high_32 , low_32 } pair.
1234+ --- @return string hex The hexadecimal string (e.g. , " 0000180000001000" ).
1235+ function bit64 .to_hex (value )
1236+ return string.format (" %08X%08X" , value [1 ], value [2 ])
1237+ end
1238+
1239+ --- Converts a {high, low} pair to a Lua number.
1240+ --- Warning: Lua numbers use 64-bit IEEE 754 doubles with 53-bit mantissa precision.
1241+ --- Values exceeding 53 bits (greater than 9007199254740991) will lose precision.
1242+ --- To maintain full 64-bit precision, keep values in {high, low} format.
1243+ --- @param value Int64HighLow The {high_32 , low_32 } pair.
1244+ --- @param strict ? boolean If true , errors when value exceeds 53-bit precision.
1245+ --- @return number result The value as a Lua number (may lose precision for large values unless strict ).
1246+ function bit64 .to_number (value , strict )
1247+ if strict and value [1 ] > 0x001FFFFF then
1248+ error (" Value exceeds 53-bit precision (max: 9007199254740991)" , 2 )
1249+ end
1250+ return value [1 ] * 0x100000000 + value [2 ]
1251+ end
1252+
1253+ --- Creates a {high, low} pair from a Lua number.
1254+ --- @param value number The number to convert.
1255+ --- @return Int64HighLow pair The {high_32 , low_32 } pair.
1256+ function bit64 .from_number (value )
1257+ local low = value % 0x100000000
1258+ local high = math.floor (value / 0x100000000 )
1259+ return bit64 .new (high , low )
1260+ end
1261+
1262+ --- Checks if two {high, low} pairs are equal.
1263+ --- @param a Int64HighLow The first {high_32 , low_32 } pair.
1264+ --- @param b Int64HighLow The second {high_32 , low_32 } pair.
1265+ --- @return boolean equal True if the values are equal.
1266+ function bit64 .eq (a , b )
1267+ return a [1 ] == b [1 ] and a [2 ] == b [2 ]
1268+ end
1269+
1270+ --- Checks if a {high, low} pair is zero.
1271+ --- @param value Int64HighLow The {high_32 , low_32 } pair.
1272+ --- @return boolean is_zero True if the value is zero.
1273+ function bit64 .is_zero (value )
1274+ return value [1 ] == 0 and value [2 ] == 0
1275+ end
1276+
12281277---- ----------------------------------------------------------------------------
12291278-- Aliases for compatibility
12301279---- ----------------------------------------------------------------------------
@@ -1531,6 +1580,90 @@ function bit64.selftest()
15311580 inputs = { string.char (0xF0 , 0xDE , 0xBC , 0x9A , 0x78 , 0x56 , 0x34 , 0x12 ) },
15321581 expected = { 0x12345678 , 0x9ABCDEF0 },
15331582 },
1583+
1584+ -- to_hex tests
1585+ {
1586+ name = " to_hex({0x00001800, 0x00001000})" ,
1587+ fn = bit64 .to_hex ,
1588+ inputs = { { 0x00001800 , 0x00001000 } },
1589+ expected = " 0000180000001000" ,
1590+ },
1591+ {
1592+ name = " to_hex({0xFFFFFFFF, 0xFFFFFFFF})" ,
1593+ fn = bit64 .to_hex ,
1594+ inputs = { { 0xFFFFFFFF , 0xFFFFFFFF } },
1595+ expected = " FFFFFFFFFFFFFFFF" ,
1596+ },
1597+ {
1598+ name = " to_hex({0x00000000, 0x00000000})" ,
1599+ fn = bit64 .to_hex ,
1600+ inputs = { { 0x00000000 , 0x00000000 } },
1601+ expected = " 0000000000000000" ,
1602+ },
1603+
1604+ -- to_number tests
1605+ {
1606+ name = " to_number({0x00000000, 0x00000001})" ,
1607+ fn = bit64 .to_number ,
1608+ inputs = { { 0x00000000 , 0x00000001 } },
1609+ expected = 1 ,
1610+ },
1611+ {
1612+ name = " to_number({0x00000000, 0xFFFFFFFF})" ,
1613+ fn = bit64 .to_number ,
1614+ inputs = { { 0x00000000 , 0xFFFFFFFF } },
1615+ expected = 4294967295 ,
1616+ },
1617+ {
1618+ name = " to_number({0x00000001, 0x00000000})" ,
1619+ fn = bit64 .to_number ,
1620+ inputs = { { 0x00000001 , 0x00000000 } },
1621+ expected = 4294967296 ,
1622+ },
1623+
1624+ -- from_number tests
1625+ {
1626+ name = " from_number(1)" ,
1627+ fn = bit64 .from_number ,
1628+ inputs = { 1 },
1629+ expected = { 0x00000000 , 0x00000001 },
1630+ },
1631+ {
1632+ name = " from_number(4294967296)" ,
1633+ fn = bit64 .from_number ,
1634+ inputs = { 4294967296 },
1635+ expected = { 0x00000001 , 0x00000000 },
1636+ },
1637+ {
1638+ name = " from_number(0)" ,
1639+ fn = bit64 .from_number ,
1640+ inputs = { 0 },
1641+ expected = { 0x00000000 , 0x00000000 },
1642+ },
1643+
1644+ -- eq tests
1645+ { name = " eq({1,2}, {1,2})" , fn = bit64 .eq , inputs = { { 1 , 2 }, { 1 , 2 } }, expected = true },
1646+ { name = " eq({1,2}, {1,3})" , fn = bit64 .eq , inputs = { { 1 , 2 }, { 1 , 3 } }, expected = false },
1647+ { name = " eq({1,2}, {2,2})" , fn = bit64 .eq , inputs = { { 1 , 2 }, { 2 , 2 } }, expected = false },
1648+
1649+ -- is_zero tests
1650+ { name = " is_zero({0,0})" , fn = bit64 .is_zero , inputs = { { 0 , 0 } }, expected = true },
1651+ { name = " is_zero({0,1})" , fn = bit64 .is_zero , inputs = { { 0 , 1 } }, expected = false },
1652+ { name = " is_zero({1,0})" , fn = bit64 .is_zero , inputs = { { 1 , 0 } }, expected = false },
1653+
1654+ -- to_number strict mode tests (values within 53-bit range)
1655+ {
1656+ name = " to_number({0x001FFFFF, 0xFFFFFFFF}, true) -- max 53-bit" ,
1657+ fn = bit64 .to_number ,
1658+ inputs = { { 0x001FFFFF , 0xFFFFFFFF }, true },
1659+ expected = 9007199254740991 ,
1660+ },
1661+ {
1662+ name = " to_number({0, 1}, true)" ,
1663+ fn = bit64 .to_number ,
1664+ inputs = { { 0 , 1 }, true },
1665+ expected = 1 ,
1666+ },
15341667 }
15351668
15361669 for _ , test in ipairs (test_vectors ) do
@@ -1705,6 +1838,24 @@ function bit64.selftest()
17051838 end
17061839 end
17071840
1841+ -- Test to_number strict mode error case
1842+ print (" \n Running to_number strict mode tests..." )
1843+ total = total + 1
1844+ local ok , err = pcall (function ()
1845+ bit64 .to_number ({ 0x00200000 , 0x00000000 }, true ) -- 2^53, exceeds 53-bit
1846+ end )
1847+ if not ok and string.find (err , " 53%-bit precision" ) then
1848+ print (" PASS: to_number strict mode errors on values > 53 bits" )
1849+ passed = passed + 1
1850+ else
1851+ print (" FAIL: to_number strict mode errors on values > 53 bits" )
1852+ if ok then
1853+ print (" Expected error but got success" )
1854+ else
1855+ print (" Expected '53-bit precision' error but got: " .. tostring (err ))
1856+ end
1857+ end
1858+
17081859 print (string.format (" \n 64-bit operations: %d/%d tests passed\n " , passed , total ))
17091860 return passed == total
17101861end
@@ -1741,7 +1892,7 @@ local bitn = {
17411892}
17421893
17431894--- Library version (injected at build time for releases).
1744- local VERSION = " v0.2 .0"
1895+ local VERSION = " v0.3 .0"
17451896
17461897--- Get the library version string.
17471898--- @return string version Version string (e.g. , " v1.0.0" or " dev" )
0 commit comments