| #ifdef __EMSCRIPTEN__ |
| #include <emscripten.h> |
| #endif |
| |
| #include "test_int53.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <time.h> |
| |
| // Uncomment to compute the expected result: |
| //#define GENERATE_ANSWERS |
| |
| EM_JS_DEPS(main, "$convertI32PairToI53,$convertU32PairToI53,$readI53FromU64,$readI53FromI64,$writeI53ToI64,$writeI53ToI64Clamped,$writeI53ToU64Clamped,$writeI53ToI64Signaling,$writeI53ToU64Signaling"); |
| |
| void writeI53ToI64_int64(int64_t *heapAddress, int64_t num) { |
| #ifdef GENERATE_ANSWERS |
| *heapAddress = num; |
| #else |
| EM_ASM(writeI53ToI64($0, $1), heapAddress, (double)num); |
| #endif |
| } |
| |
| void writeI53ToI64_uint64(uint64_t *heapAddress, uint64_t num) { |
| #ifdef GENERATE_ANSWERS |
| *heapAddress = num; |
| #else |
| EM_ASM(writeI53ToI64($0, $1), heapAddress, (double)num); |
| #endif |
| } |
| |
| void writeI53ToI64_double(int64_t *heapAddress, double num) { |
| #ifdef GENERATE_ANSWERS |
| if (num > 0 || num <= -9223372036854775808.0 /* underflow, garbage in-garbage out situation: just produce a value that matches current JS impl*/) |
| *(uint64_t*)heapAddress = (uint64_t)num; |
| else |
| *heapAddress = (int64_t)num; |
| #else |
| EM_ASM(writeI53ToI64($0, $1), heapAddress, num); |
| #endif |
| } |
| |
| void writeI53ToI64Clamped_double(int64_t *heapAddress, double num) { |
| #ifdef GENERATE_ANSWERS |
| if (num >= 9223372036854775808.0) |
| *heapAddress = 0x7FFFFFFFFFFFFFFFLL; |
| else if (num <= -9223372036854775808.0) |
| *heapAddress = -0x8000000000000000LL; |
| else if (num > 0) |
| *(uint64_t*)heapAddress = (uint64_t)num; |
| else |
| *heapAddress = (int64_t)num; |
| #else |
| EM_ASM(writeI53ToI64Clamped($0, $1), heapAddress, num); |
| #endif |
| } |
| |
| void writeI53ToI64Signaling_double(int64_t *heapAddress, double num) { |
| #ifdef GENERATE_ANSWERS |
| if (num <= -9223372036854775808.0 || num >= 9223372036854775808.0) { |
| *heapAddress = 0x0102030401020304ULL; |
| } else { |
| *heapAddress = (int64_t)num; |
| } |
| #else |
| EM_ASM(try { |
| writeI53ToI64Signaling($0, $1) |
| } catch(e) { |
| HEAPU32[($0) / 4] = 0x01020304; |
| HEAPU32[($0+4) / 4] = 0x01020304; |
| }, heapAddress, num); |
| #endif |
| } |
| |
| void writeI53ToU64Clamped_double(uint64_t *heapAddress, double num) { |
| #ifdef GENERATE_ANSWERS |
| if (num >= 18446744073709551616.0) |
| *heapAddress = 0xFFFFFFFFFFFFFFFFULL; |
| else if (num < 0) |
| *heapAddress = 0; |
| else |
| *heapAddress = (uint64_t)num; |
| #else |
| EM_ASM(writeI53ToU64Clamped($0, $1), heapAddress, num); |
| #endif |
| } |
| |
| void writeI53ToU64Signaling_double(uint64_t *heapAddress, double num) { |
| #ifdef GENERATE_ANSWERS |
| if (num < 0 || num >= 18446744073709551616.0) { |
| *heapAddress = 0x0102030401020304ULL; |
| } else { |
| *heapAddress = (uint64_t)num; |
| } |
| #else |
| EM_ASM(try { |
| writeI53ToU64Signaling($0, $1) |
| } catch(e) { |
| HEAPU32[$0 / 4] = 0x01020304; |
| HEAPU32[($0+4) / 4] = 0x01020304; |
| } , heapAddress, num); |
| #endif |
| } |
| |
| int64_t readI53FromI64_toInt64(int64_t *heapAddress) { |
| #ifdef GENERATE_ANSWERS |
| return *heapAddress; |
| #else |
| return (int64_t)EM_ASM_DOUBLE(return readI53FromI64($0), heapAddress); |
| #endif |
| } |
| |
| double readI53FromI64(int64_t *heapAddress) |
| { |
| #ifdef GENERATE_ANSWERS |
| return (double)*heapAddress; |
| #else |
| return EM_ASM_DOUBLE(return readI53FromI64($0), heapAddress); |
| #endif |
| } |
| |
| int64_t readI53FromU64_toInt64(uint64_t *heapAddress) { |
| #ifdef GENERATE_ANSWERS |
| return (int64_t)*heapAddress; |
| #else |
| return (int64_t)EM_ASM_DOUBLE(return readI53FromU64($0), heapAddress); |
| #endif |
| } |
| |
| uint64_t readI53FromU64_toUInt64(uint64_t *heapAddress) { |
| #ifdef GENERATE_ANSWERS |
| return (uint64_t)*heapAddress; |
| #else |
| return (uint64_t)EM_ASM_DOUBLE(return readI53FromU64($0), heapAddress); |
| #endif |
| } |
| |
| double readI53FromU64(uint64_t *heapAddress) { |
| #ifdef GENERATE_ANSWERS |
| return (double)*heapAddress; |
| #else |
| return EM_ASM_DOUBLE(return readI53FromU64($0), heapAddress); |
| #endif |
| } |
| |
| int64_t convertI32PairToI53(int32_t lo, int32_t hi) { |
| #ifdef GENERATE_ANSWERS |
| uint64_t val = (uint32_t)lo; |
| val |= ((uint64_t)(uint32_t)hi) << 32; |
| return (int64_t)val; |
| #else |
| return (int64_t)EM_ASM_DOUBLE(return convertI32PairToI53($0, $1), lo, hi); |
| #endif |
| } |
| |
| uint64_t convertU32PairToI53(uint32_t lo, uint32_t hi) { |
| #ifdef GENERATE_ANSWERS |
| uint64_t val = (uint32_t)lo; |
| val |= ((uint64_t)(uint32_t)hi) << 32; |
| return val; |
| #else |
| return (uint64_t)EM_ASM_DOUBLE(return convertU32PairToI53($0, $1), lo, hi); |
| #endif |
| } |
| |
| int64_t testconvertI32PairToI53(int64_t val) { |
| uint64_t u = (uint64_t)val; |
| int32_t lo = (uint32_t)u; |
| int32_t hi = u >> 32; |
| return convertI32PairToI53(lo, hi); |
| } |
| |
| uint64_t testconvertU32PairToI53(uint64_t val) { |
| uint32_t lo = (uint32_t)val; |
| uint32_t hi = val >> 32; |
| return convertU32PairToI53(lo, hi); |
| } |
| |
| int64_t testWriteI64AsI53(int64_t num) { |
| int64_t addr = 0; |
| writeI53ToI64_int64(&addr, num); |
| return addr; |
| } |
| |
| int64_t testReadWriteI64AsI53(int64_t num) { |
| int64_t addr = 0; |
| writeI53ToI64_int64(&addr, num); |
| return readI53FromI64_toInt64(&addr); |
| } |
| |
| uint64_t testReadWriteU64AsI53(uint64_t num) { |
| uint64_t addr = 0; |
| writeI53ToI64_uint64((uint64_t*)&addr, num); |
| return readI53FromU64_toUInt64(&addr); |
| } |
| |
| int main() { |
| printf("Testing positive losslessIntegers:\n"); |
| for (int i = 0; i < sizeof(losslessIntegers) / sizeof(losslessIntegers[0]); ++i) { |
| uint64_t num = losslessIntegers[i]; |
| printf("%llu (0x%llx):\n", num, num); |
| printf(" convertI32PairToI53: 0x%llx\n", testconvertI32PairToI53(num)); |
| if (num != testconvertI32PairToI53(num)) return 1; |
| printf(" convertU32PairToI53: 0x%llx\n", testconvertU32PairToI53(num)); |
| if (num != testconvertU32PairToI53(num)) return 1; |
| printf(" writeI53ToI64: 0x%llx\n", testWriteI64AsI53(num)); |
| if (num != testWriteI64AsI53(num)) return 1; |
| printf(" readI53FromI64: 0x%llx\n", testReadWriteI64AsI53(num)); |
| if (num != testReadWriteI64AsI53(num)) return 1; |
| printf(" readI53FromU64: 0x%llx\n", testReadWriteU64AsI53(num)); |
| if (num != testReadWriteU64AsI53(num)) return 1; |
| printf("\n"); |
| } |
| |
| printf("Testing negative losslessIntegers:\n"); |
| for (int i = 0; i < sizeof(losslessIntegers) / sizeof(losslessIntegers[0]); ++i) { |
| // Test negative: |
| int64_t neg = -(int64_t)losslessIntegers[i]; |
| printf("%lld (0x%llx):\n", neg, neg); |
| printf(" convertI32PairToI53: 0x%llx\n", testconvertI32PairToI53(neg)); |
| if (neg != testconvertI32PairToI53(neg)) return 1; |
| printf(" writeI53ToI64: 0x%llx\n", testWriteI64AsI53(neg)); |
| if (neg != testWriteI64AsI53(neg)) return 1; |
| printf(" readI53FromI64: 0x%llx\n", testReadWriteI64AsI53(neg)); |
| if (neg != testReadWriteI64AsI53(neg)) return 1; |
| printf("\n"); |
| } |
| |
| printf("Testing preciseUnsignedIntegers:\n"); |
| for (int i = 0; i < sizeof(preciseUnsignedIntegers) / sizeof(preciseUnsignedIntegers[0]); ++i) { |
| uint64_t num = preciseUnsignedIntegers[i]; |
| printf("%llu (0x%llx):\n", num, num); |
| printf(" convertU32PairToI53: 0x%llx: error difference: %lld\n", testconvertU32PairToI53(num), testconvertU32PairToI53(num) - num); |
| printf(" readI53FromU64: 0x%llx: error difference: %lld\n", testReadWriteU64AsI53(num), testReadWriteU64AsI53(num) - num); |
| printf("\n"); |
| } |
| |
| printf("Testing preciseNegativeIntegers:\n"); |
| for (int i = 0; i < sizeof(preciseNegativeIntegers) / sizeof(preciseNegativeIntegers[0]); ++i) { |
| uint64_t num = preciseNegativeIntegers[i]; |
| printf("%llu (0x%llx):\n", num, num); |
| printf(" convertI32PairToI53: 0x%llx: error difference: %lld\n", testconvertI32PairToI53(num), testconvertI32PairToI53(num) - num); |
| printf(" readI53FromI64: 0x%llx: error difference: %lld\n", testReadWriteI64AsI53(num), testReadWriteI64AsI53(num) - num); |
| printf("\n"); |
| } |
| |
| printf("Testing impreciseUnsignedIntegers:\n"); |
| for (int i = 0; i < sizeof(impreciseUnsignedIntegers) / sizeof(impreciseUnsignedIntegers[0]); ++i) { |
| double num = impreciseUnsignedIntegers[i]; |
| printf("%f:\n", num); |
| uint64_t u; |
| writeI53ToI64_double((int64_t*)&u, num); |
| printf(" writeI53ToI64: 0x%llx (%llu): error difference: %g\n", u, u, u - num); |
| printf("\n"); |
| } |
| |
| printf("Testing impreciseNegativeIntegers:\n"); |
| for (int i = 0; i < sizeof(impreciseNegativeIntegers) / sizeof(impreciseNegativeIntegers[0]); ++i) { |
| double num = impreciseNegativeIntegers[i]; |
| printf("%f:\n", num); |
| int64_t u; |
| writeI53ToI64_double(&u, num); |
| printf(" writeI53ToI64: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| printf("\n"); |
| } |
| |
| printf("Testing otherDoubles:\n"); |
| for (int i = 0; i < sizeof(otherDoubles) / sizeof(otherDoubles[0]); ++i) { |
| for (int sign = 0; sign < 2; ++sign) { |
| double num = otherDoubles[i]; |
| if (sign) { |
| num = -num; |
| } |
| printf("%f:\n", num); |
| int64_t u; |
| writeI53ToI64_double(&u, num); |
| printf(" writeI53ToI64: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| writeI53ToI64Clamped_double(&u, num); |
| printf(" writeI53ToI64Clamped: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| writeI53ToI64Signaling_double(&u, num); |
| if (u == 0x0102030401020304) |
| printf(" writeI53ToI64Signaling: (RangeError)\n"); |
| else |
| printf(" writeI53ToI64Signaling: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| writeI53ToU64Clamped_double((uint64_t*)&u, num); |
| printf(" writeI53ToU64Clamped: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| writeI53ToU64Signaling_double((uint64_t*)&u, num); |
| if (u == 0x0102030401020304) |
| printf(" writeI53ToU64Signaling: (RangeError)\n"); |
| else |
| printf(" writeI53ToU64Signaling: 0x%llx (%lld): error difference: %g\n", u, u, u - num); |
| printf("\n"); |
| } |
| } |
| |
| printf("All done!\n"); |
| } |