#if 0 /* #/ ================================================================ #/ #/ rf64.c #/ #/ Probabalistic floating-point numbers #/ #/ ---------------------------------------------------------------- #/ #/ (C) 2024 Mitya Selivanov , MIT License #/ #/ ================================================================ #/ #/ Self-compilation shell script #/ SRC=${0##*./} BIN=${SRC%.*} gcc \ -Wall -Wextra -Werror -pedantic \ -Wno-old-style-declaration \ -Wno-missing-braces \ -Wno-unused-variable \ -Wno-unused-but-set-variable \ -Wno-unused-parameter \ -Wno-overlength-strings \ -O3 \ -fsanitize=undefined,address,leak -mshstk \ -D RF64_TESTS \ -o $BIN $SRC && \ ./$BIN $@ && rm $BIN exit $? # */ #endif // ================================================================ #ifndef TYPES_HEADER_GUARD_ #define TYPES_HEADER_GUARD_ typedef signed char i8; typedef signed short i16; typedef signed i32; typedef signed long long i64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned u32; typedef unsigned long long u64; typedef char c8; typedef int c32; typedef signed char b8; typedef float f32; typedef double f64; #endif // TYPES_HEADER_GUARD_ // ================================================================ #ifndef RF64_HEADER_GUARD_ #define RF64_HEADER_GUARD_ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #ifndef RF64_RAND static i32 rf64_rand(i32 min, i32 max) { if (max <= min) return min; return min + (rand() % (max - min + 1)); } #define RF64_RAND(min, max) rf64_rand((min), (max)) #endif #define RF64_EXPONENT_NUM_BITS 30 #define RF64_MANTISSA_NUM_BITS 32 #define RF64_EXPONENT_ZERO (1 << (RF64_EXPONENT_NUM_BITS / 2)) #define RF64_EXPONENT_MAX ((1 << RF64_EXPONENT_NUM_BITS) - 1) #define RF64_MANTISSA_MAX 0xffffffffu typedef struct { u32 infinity : 1; u32 sign : 1; i32 exponent : RF64_EXPONENT_NUM_BITS; u32 mantissa; } rf64; rf64 rf64_from_i64(i64 x); i64 i64_from_rf64(rf64 x); void rf64_inc(rf64 *x); void rf64_dec(rf64 *x); void rf64_add(rf64 *x, rf64 y); void rf64_sub(rf64 *x, rf64 y); void rf64_mul(rf64 *x, rf64 y); void rf64_div(rf64 *x, rf64 y); #endif // RF64_HEADER_GUARD_ #ifndef RF64_HEADER #ifndef RF64_IMPL_GUARD_ #define RF64_IMPL_GUARD_ rf64 rf64_from_i64(i64 x) { rf64 z = { .sign = x < 0, .exponent = RF64_EXPONENT_ZERO, }; u64 a = z.sign ? -x : x; while (a > RF64_MANTISSA_MAX) { u64 loss_comp = (a & 1) == 1 ? RF64_RAND(0, 1) : 0; z.exponent += 1; a /= 2; a += loss_comp; } z.mantissa = (u32) a; return z; } i64 i64_from_rf64(rf64 x) { assert(0); } void rf64_inc(rf64 *x) { assert(0); } void rf64_dec(rf64 *x) { assert(x != NULL); if (x == NULL) return; assert(0); } void rf64_add(rf64 *x, rf64 y) { assert(x != NULL); if (x == NULL) return; assert(0); } void rf64_sub(rf64 *x, rf64 y) { assert(x != NULL); if (x == NULL) return; assert(0); } void rf64_mul(rf64 *x, rf64 y) { assert(x != NULL); if (x == NULL) return; assert(0); } void rf64_div(rf64 *x, rf64 y) { assert(x != NULL); if (x == NULL) return; assert(0); } #ifdef RF64_TESTS #include #include void report_test(c8 *name, b8 success) { i32 l = 20 - (i32) strlen(name); printf("%s %.*s %s\n", name, l < 1 ? 1 : l, "....................", success ? "OK" : "FAIL" ); } #define TEST_(x) report_test(#x, test_##x()) b8 test_from_i64() { return 1 && rf64_from_i64( 0 ).infinity == 0 && rf64_from_i64( 0 ).sign == 0 && rf64_from_i64( 0 ).exponent == RF64_EXPONENT_ZERO && rf64_from_i64( 0 ).mantissa == 0 && rf64_from_i64( 42 ).infinity == 0 && rf64_from_i64( 42 ).sign == 0 && rf64_from_i64( 42 ).exponent == RF64_EXPONENT_ZERO && rf64_from_i64( 42 ).mantissa == 42 && rf64_from_i64(-42 ).infinity == 0 && rf64_from_i64(-42 ).sign == 1 && rf64_from_i64(-42 ).exponent == RF64_EXPONENT_ZERO && rf64_from_i64(-42 ).mantissa == 42 && rf64_from_i64( 0xffffffff ).infinity == 0 && rf64_from_i64( 0xffffffff ).sign == 0 && rf64_from_i64( 0xffffffff ).exponent == RF64_EXPONENT_ZERO && rf64_from_i64( 0xffffffff ).mantissa == 0xffffffff && rf64_from_i64(-0xffffffffll ).infinity == 0 && rf64_from_i64(-0xffffffffll ).sign == 1 && rf64_from_i64(-0xffffffffll ).exponent == RF64_EXPONENT_ZERO && rf64_from_i64(-0xffffffffll ).mantissa == 0xffffffff && rf64_from_i64( 0x100000000ll).infinity == 0 && rf64_from_i64( 0x100000000ll).sign == 0 && rf64_from_i64( 0x100000000ll).exponent == RF64_EXPONENT_ZERO + 1 && rf64_from_i64( 0x100000000ll).mantissa == 0x80000000u && rf64_from_i64(-0x100000000ll).infinity == 0 && rf64_from_i64(-0x100000000ll).sign == 1 && rf64_from_i64(-0x100000000ll).exponent == RF64_EXPONENT_ZERO + 1 && rf64_from_i64(-0x100000000ll).mantissa == 0x80000000u && 1; } b8 test_to_i64() { return 1 && i64_from_rf64(rf64_from_i64( 0 )) == 0 && i64_from_rf64(rf64_from_i64( 1 )) == 1 && i64_from_rf64(rf64_from_i64(-1 )) == -1 && i64_from_rf64(rf64_from_i64( 42 )) == 42 && i64_from_rf64(rf64_from_i64(-42 )) == -42 && i64_from_rf64(rf64_from_i64( 0xffffffff )) == 0xffffffff && i64_from_rf64(rf64_from_i64(-0xffffffff )) == -0xffffffff && i64_from_rf64(rf64_from_i64( 0x100000000ll )) == 0x100000000ll && i64_from_rf64(rf64_from_i64(-0x100000000ll )) == -0x100000000ll && i64_from_rf64(rf64_from_i64( 0x42000000000ll)) == 0x42000000000ll && i64_from_rf64(rf64_from_i64(-0x42000000000ll)) == -0x42000000000ll && 1; } i32 main(i32 argc, c8 **argv) { (void) argc; (void) argv; TEST_(from_i64); TEST_(to_i64); return 0; } #undef TEST_ #endif // RF64_TESTS #endif // RF64_IMPL_GUARD_ #endif // RF64_HEADER