├── tools ├── bithacks │ ├── Makefile │ └── unsigned-division-by-constant.c └── random │ ├── freqency.gp │ ├── permute │ ├── candidates │ │ ├── kensler.c │ │ ├── kensler-splittable64.c │ │ └── camel-cdr.c │ ├── Makefile │ ├── bench.c │ ├── plot.sh │ ├── rng-shuffle.c │ ├── evalpow2.c │ ├── README.md │ └── res │ │ └── 0n64q24.svg │ ├── extra-xmacros.h │ ├── Makefile │ ├── zig.gp │ ├── testu01.c │ ├── ziggurat-constants.c │ ├── rng.c │ ├── bench.c │ ├── dist.c │ └── extra.h ├── .github └── workflows │ └── tests.yml ├── test ├── Makefile ├── arena-allocator.c ├── test.sh ├── random │ ├── jump.c │ ├── dist_uniform.c │ ├── shuf.c │ ├── dist_uniform_dense.c │ └── dist_normal.c └── stretchy-buffer │ ├── test.c │ └── xtest.h ├── LICENSE ├── cauldron ├── random-xmacros.h ├── test.h ├── arena-allocator.h ├── arg.h ├── stretchy-buffer.h ├── bench.h └── random-xoroshiro128-jump.h ├── Makefile ├── ideas └── fmt.c └── README.md /tools/bithacks/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | CC = c99 3 | CFLAGS = -I../../ 4 | LDLIBS = -lm 5 | 6 | all: unsigned-division-by-constant 7 | 8 | unsigned-division-by-constant: unsigned-division-by-constant.c 9 | 10 | clean: 11 | rm -f unsigned-division-by-constant 12 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | Tests: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Run Test 15 | run: make -j$(nproc) -C test 16 | -------------------------------------------------------------------------------- /tools/random/freqency.gp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gnuplot -c 2 | 3 | set terminal x11 enhanced persist 4 | 5 | if (0) { 6 | set terminal dumb 38 20 7 | set xtics 1 8 | set ytics 50 9 | } 10 | 11 | if (ARG1) { 12 | bw = ARG1 13 | } else { 14 | bw = 0.1 15 | } 16 | 17 | # Adopted from "http://www.phyast.pitt.edu/~zov1/" 18 | 19 | unset key 20 | set boxwidth 0.7 relative 21 | set style fill solid 1.0 noborder 22 | bin(x, width) = width * floor(x / width) 23 | plot '/dev/stdin' using (bin($1, bw)):(1.0) smooth frequency with boxes 24 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | all: arena-allocator random-target streachy-buffer-target 4 | 5 | arena-allocator: 6 | ./test.sh arena-allocator.c c89 7 | 8 | random-target: random-shuf random-jump random-dist-normal random-dist-uniform \ 9 | random-dist-uniform-dense 10 | random-shuf: 11 | ./test.sh random/shuf.c c++ c89 12 | random-jump: 13 | ./test.sh random/jump.c c++ c89 14 | random-dist-normal: 15 | ./test.sh random/dist_normal.c c++ c89 16 | random-dist-uniform: 17 | ./test.sh random/dist_uniform.c c++ c89 18 | random-dist-uniform-dense: 19 | ./test.sh random/dist_uniform_dense.c c++ c99 20 | 21 | streachy-buffer-target: 22 | ./test.sh stretchy-buffer/test.c c89 23 | -------------------------------------------------------------------------------- /tools/random/permute/candidates/kensler.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t 4 | hash(uint64_t idx, uint64_t mask, uint64_t seed) 5 | { 6 | seed &= UINT32_MAX; 7 | 8 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 9 | idx ^= seed; idx *= 0xE170893D; 10 | idx ^= seed >> 16; 11 | idx ^= (idx & mask) >> 4; 12 | idx ^= seed >> 8; idx *= 0x0929EB3F; 13 | idx ^= seed >> 23; 14 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 15 | idx *= 0x6935FA69; 16 | idx ^= (idx & mask) >> 11; idx *= 0x74DCB303; 17 | idx ^= (idx & mask) >> 2; idx *= 0x9E501CC3; 18 | idx ^= (idx & mask) >> 2; idx *= 0xC860A3DF; 19 | idx &= mask; 20 | idx ^= idx >> 5; 21 | return (idx ^ seed) & mask; 22 | } 23 | -------------------------------------------------------------------------------- /test/arena-allocator.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ARENA_ALLOCATOR_IMPLEMENT 4 | #include 5 | #include 6 | 7 | int 8 | main(void) 9 | { 10 | int i; 11 | aa_Arena a = { 0 }; 12 | 13 | TEST_BEGIN(("arena-allocator")); 14 | 15 | #define TEST_X(T, v) \ 16 | do { \ 17 | T *x = aa_alloc(&a, sizeof *x); \ 18 | TEST_ASSERT(x); \ 19 | *x = (v); \ 20 | TEST_ASSERT(*x == (v)); \ 21 | } while (0) 22 | 23 | for (i = 0; i < 32; ++i) { 24 | TEST_X(char, 'u'); 25 | TEST_X(char, 'w'); 26 | TEST_X(char, 'u'); 27 | TEST_X(long, 31415926L); 28 | TEST_X(short, 420); 29 | TEST_X(double, 420.69); 30 | aa_dealloc(&a); 31 | } 32 | 33 | TEST_END(); 34 | aa_free(&a); 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /tools/random/permute/candidates/kensler-splittable64.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t 4 | hash(uint64_t idx, uint64_t mask, uint64_t seed) 5 | { 6 | idx ^= seed; 7 | /* splittable64 */ 8 | idx ^= (idx & mask) >> 30; idx *= 0xBF58476D1CE4E5B9; 9 | idx ^= (idx & mask) >> 27; idx *= 0x94D049BB133111EB; 10 | idx ^= (idx & mask) >> 31; 11 | idx *= 0xBF58476D1CE4E5B9; 12 | 13 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 14 | idx ^= seed; idx *= 0xE170893D; 15 | idx ^= seed >> 16; 16 | idx ^= (idx & mask) >> 4; 17 | idx ^= seed >> 8; idx *= 0x0929EB3F; 18 | idx ^= seed >> 23; 19 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 20 | idx *= 0x6935FA69; 21 | idx ^= (idx & mask) >> 11; idx *= 0x74DCB303; 22 | idx ^= (idx & mask) >> 2; idx *= 0x9E501CC3; 23 | idx ^= (idx & mask) >> 2; idx *= 0xC860A3DF; 24 | idx &= mask; 25 | idx ^= idx >> 5; 26 | return idx; 27 | } 28 | -------------------------------------------------------------------------------- /tools/random/permute/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | CC = cc 3 | CFLAGS = -std=c99 -Wall -Wextra -march=native -Ofast -fopenmp 4 | LDLIBS = -lm -ldl 5 | 6 | hashes = \ 7 | candidates/camel-cdr.so \ 8 | candidates/kensler.so \ 9 | candidates/kensler-splittable64.so 10 | 11 | compile: bench evalpow2 rng-shuffle $(hashes) 12 | 13 | bench: bench.c 14 | $(CC) $(LDFLAGS) $(CFLAGS) -o $@ bench.c $(LDLIBS) 15 | 16 | evalpow2: evalpow2.c 17 | $(CC) $(LDFLAGS) $(CFLAGS) -o $@ evalpow2.c $(LDLIBS) 18 | 19 | rng-shuffle: rng-shuffle.c 20 | $(CC) $(LDFLAGS) $(CFLAGS) -o $@ rng-shuffle.c $(LDLIBS) 21 | 22 | candidates/camel-cdr.so: candidates/camel-cdr.c 23 | candidates/kensler.so: candidates/kensler.c 24 | candidates/kensler-splittable64.so: candidates/kensler-splittable64.c 25 | 26 | clean: 27 | rm -f bench evalpow2 rng-shuffle $(hashes) 28 | 29 | .SUFFIXES: .so .c 30 | .c.so: 31 | $(CC) -shared $(LDFLAGS) -fPIC $(CFLAGS) -o $@ $< 32 | -------------------------------------------------------------------------------- /tools/random/extra-xmacros.h: -------------------------------------------------------------------------------- 1 | RANDOM_X16(PRNG16Msws, prng16_msws, prng16_msws_randomize) 2 | RANDOM_X16(PRNG16Sfc, prng16_sfc, prng16_sfc_randomize) 3 | 4 | RANDOM_X32(PRNG32Msws, prng32_msws, prng32_msws_randomize) 5 | RANDOM_X32(PRNG32Sfc, prng32_sfc, prng32_sfc_randomize) 6 | RANDOM_X32(PRNG32Jfs, prng32_jfs, prng32_jfs_randomize) 7 | RANDOM_X32(PRNG32JavaUtilRandom, prng32_java_util_random, prng32_java_util_random_randomize) 8 | 9 | #if __SIZEOF_INT128__ 10 | RANDOM_X64(PRNG64Msws, prng64_msws, prng64_msws_randomize) 11 | #endif 12 | RANDOM_X64(PRNG64Msws64_2x32, prng64_msws_2x32bit, prng64_msws_2x32bit_randomize) 13 | RANDOM_X64(PRNG64Sfc, prng64_sfc, prng64_sfc_randomize) 14 | RANDOM_X64(PRNG64Tylo, prng64_tylo, prng64_tylo_randomize) 15 | RANDOM_X64(PRNG64Jfs, prng64_jfs, prng64_jfs_randomize) 16 | RANDOM_X64(PRNG64Xorshift128p, prng64_xorshift128p, prng64_xorshift128p_randomize) 17 | RANDOM_X64(PRNG64Xorshift64, prng64_xorshift64, prng64_xorshift64_randomize) 18 | 19 | -------------------------------------------------------------------------------- /tools/random/Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | CC = c99 3 | CFLAGS=-I../../ 4 | 5 | BIN = dist rng bench ziggurat-constants 6 | 7 | all: $(BIN) 8 | 9 | testu01: testu01.c 10 | $(CC) $(CFLAGS) -O2 -o $@ -ltestu01 testu01.c 11 | 12 | ziggurat-constants: ziggurat-constants.c 13 | $(CC) $(CFLAGS) -O2 -o $@ -lm ziggurat-constants.c 14 | 15 | PractRand: 16 | wget https://downloads.sourceforge.net/project/pracrand/PractRand-pre0.95.zip 17 | unzip PractRand-pre0.95.zip -d tmp 18 | rm PractRand-pre0.95.zip 19 | clang++ $(CFLAGS) -Ofast \ 20 | tmp/tools/RNG_test.cpp tmp/src/*.cpp \ 21 | tmp/src/RNGs/*.cpp tmp/src/RNGs/other/*.cpp \ 22 | -Itmp/include -pthread -std=gnu++11 -o $@ 23 | rm -rf tmp 24 | 25 | dist: dist.c 26 | $(CC) $(CFLAGS) -Ofast -o $@ -lm dist.c 27 | 28 | rng: rng.c extra.h 29 | $(CC) $(CFLAGS) -march=native -Ofast -o $@ -lm rng.c 30 | 31 | bench: bench.c extra.h 32 | gcc $(CFLAGS) -march=native -Ofast -o $@ -lm bench.c 33 | 34 | clean: 35 | rm -f $(BIN) testu01 PractRand 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Olaf Bernstein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tools/random/permute/candidates/camel-cdr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t 4 | hash(uint64_t idx, uint64_t mask, uint64_t seed) 5 | { 6 | idx ^= seed; 7 | /* splittable64 */ 8 | idx ^= (idx & mask) >> 30; idx *= 0xBF58476D1CE4E5B9; 9 | idx ^= (idx & mask) >> 27; idx *= 0x94D049BB133111EB; 10 | idx ^= (idx & mask) >> 31; 11 | idx *= 0xBF58476D1CE4E5B9; 12 | 13 | idx ^= seed >> 32; 14 | idx &= mask; 15 | idx *= 0xED5AD4BB; 16 | 17 | idx ^= seed >> 48; 18 | ///* hash16_xm3 */ 19 | idx ^= (idx & mask) >> 7; idx *= 0x2993; 20 | idx ^= (idx & mask) >> 5; idx *= 0xE877; 21 | idx ^= (idx & mask) >> 9; idx *= 0x0235; 22 | idx ^= (idx & mask) >> 10; 23 | 24 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 25 | idx ^= seed; idx *= 0xE170893D; 26 | idx ^= seed >> 16; 27 | idx ^= (idx & mask) >> 4; 28 | idx ^= seed >> 8; idx *= 0x0929EB3F; 29 | idx ^= seed >> 23; 30 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 31 | idx *= 0x6935FA69; 32 | idx ^= (idx & mask) >> 11; idx *= 0x74DCB303; 33 | idx ^= (idx & mask) >> 2; idx *= 0x9E501CC3; 34 | idx ^= (idx & mask) >> 2; idx *= 0xC860A3DF; 35 | idx &= mask; 36 | idx ^= idx >> 5; 37 | return idx; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cpp=0 4 | 5 | 6 | CFLAGS="-I../ -lm -Wall -Wextra -Wsign-conversion -Werror=vla -Wno-type-limits -Wno-unused -pedantic -ggdb3 " 7 | CXXFLAGS="-I../ -lm -Wall -Wextra -Wsign-conversion -Werror=vla -Wno-type-limits -Wno-unused -pedantic -xc++ -ggdb3 " 8 | 9 | out=$(mktemp) 10 | trap '{ rm -f -- "$out"; }' EXIT 11 | 12 | 13 | in=$1 14 | shift 1 15 | for var in "$@" 16 | do 17 | [ "$var" = "c++" ] && cpp=1 18 | [ "$var" = "c89" ] && CVER="-Dinline= -std=c89 " 19 | [ "$var" = "c99" ] && CVER="-std=c99 " 20 | [ "$var" = "c11" ] && CVER="-std=c11 " 21 | done 22 | 23 | 24 | gcc $CFLAGS $in -o $out && $out 25 | 26 | CFLAGS=$CFLAGS$CVER 27 | 28 | # Test with sanitizers 29 | gcc $CFLAGS -fsanitize=address,undefined,leak -ftrapv $in -o $out && $out 30 | 31 | # Test with valgrind 32 | if which valgrind >/dev/null 33 | then 34 | gcc $CFLAGS $in -o $out && valgrind -q $out 35 | fi 36 | 37 | # Test on big endian mips if available 38 | if which mips-linux-gnu-gcc qemu-mips >/dev/null 39 | then 40 | mips-linux-gnu-gcc -I../ -ggdb -static $in -lm -o $out && qemu-mips $out 41 | fi 42 | 43 | # Test C++ 44 | [ $cpp -eq 1 ] && g++ $CXXFLAGS -xc++ $in -o $out && $out 45 | 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /tools/random/zig.gp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gnuplot -c 2 | 3 | #set terminal dumb size 46,16 4 | set terminal x11 enhanced persist linewidth 2 5 | 6 | unset label 7 | 8 | set xtics("x1" 1.9149282638037441, "x2" 1.4371588314146466, "x3" 0.9820090215959187); 9 | set ytics("y0" 0.1598570776303767,"y1" 0.3560398011641235, "y2" 0.6174415571516484, "y3" 1.0000000000000000); 10 | 11 | set xrange [0:3.5] 12 | set yrange [0:1.05] 13 | plot '-' ti "" w l ls 2, \ 14 | '' ti "" w l ls 0,\ 15 | exp(-x**2/2) title "exp(-x^2/2)" w l ls 1 16 | 0.0000000000000000 1.0000000000000000 17 | 0.9820090215959187 1.0000000000000000 18 | 0.9820090215959187 0.6174415571516484 19 | 20 | 0.0000000000000000 0.6174415571516484 21 | 1.4371588314146466 0.6174415571516484 22 | 1.4371588314146466 0.3560398011641235 23 | 24 | 0.0000000000000000 0.3560398011641235 25 | 1.9149282638037441 0.3560398011641235 26 | 1.9149282638037441 0.1598570776303767 27 | 28 | 0.0000000000000000 0.1598570776303767 29 | 1.9149282638037441 0.1598570776303767 30 | e 31 | 0.9820090215959187 0.6174415571516484 32 | 0.9820090215959187 0.3560398011641235 33 | 34 | 1.4371588314146466 0.3560398011641235 35 | 1.4371588314146466 0.1598570776303767 36 | 37 | 1.9149282638037441 0.1598570776303767 38 | 1.9149282638037441 0.0000000000000000 39 | e 40 | -------------------------------------------------------------------------------- /cauldron/random-xmacros.h: -------------------------------------------------------------------------------- 1 | RANDOM_X32(PRNG32Pcg, prng32_pcg, prng32_pcg_randomize) 2 | RANDOM_X32(PRNG32RomuTrio, prng32_romu_trio, prng32_romu_trio_randomize) 3 | RANDOM_X32(PRNG32RomuQuad, prng32_romu_quad, prng32_romu_quad_randomize) 4 | RANDOM_X32(PRNG32Xoroshiro64, prng32_xoroshiro64s, prng32_xoroshiro64_randomize) 5 | RANDOM_X32(PRNG32Xoroshiro64, prng32_xoroshiro64ss, prng32_xoroshiro64_randomize) 6 | RANDOM_X32(PRNG32Xoshiro128, prng32_xoshiro128s, prng32_xoshiro128_randomize) 7 | RANDOM_X32(PRNG32Xoshiro128, prng32_xoshiro128ss, prng32_xoshiro128_randomize) 8 | RANDOM_X32(CSPRNG32Chacha, csprng32_chacha, csprng32_chacha_randomize) 9 | 10 | #if PRNG64_PCG_AVAILABLE 11 | RANDOM_X64(PRNG64Pcg, prng64_pcg, prng64_pcg_randomize) 12 | #endif 13 | RANDOM_X64(PRNG64RomuDuo, prng64_romu_duo, prng64_romu_duo_randomize) 14 | RANDOM_X64(PRNG64RomuDuo, prng64_romu_duo_jr, prng64_romu_duo_randomize) 15 | RANDOM_X64(PRNG64RomuTrio, prng64_romu_trio, prng64_romu_trio_randomize) 16 | RANDOM_X64(PRNG64RomuQuad, prng64_romu_quad, prng64_romu_quad_randomize) 17 | RANDOM_X64(PRNG64Xoroshiro128, prng64_xoroshiro128p, prng64_xoroshiro128_randomize) 18 | RANDOM_X64(PRNG64Xoroshiro128, prng64_xoroshiro128ss, prng64_xoroshiro128_randomize) 19 | RANDOM_X64(PRNG64Xoshiro256, prng64_xoshiro256p, prng64_xoshiro256_randomize) 20 | RANDOM_X64(PRNG64Xoshiro256, prng64_xoshiro256ss, prng64_xoshiro256_randomize) 21 | -------------------------------------------------------------------------------- /tools/random/permute/bench.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define RANDOM_H_IMPLEMENTATION 14 | #include 15 | #include 16 | 17 | 18 | static void 19 | die(char *fmt, ...) 20 | { 21 | va_list args; 22 | va_start(args, fmt); 23 | vfprintf(stderr, fmt, args); 24 | va_end(args); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | #define N (1uLL << 30) 29 | 30 | int 31 | main(int argc, char **argv) 32 | { 33 | 34 | char *argv0 = argv[0]; 35 | 36 | for (char **it = argv+1; *it; ++it) { 37 | uint64_t (*hash)(uint64_t i, uint64_t mask, uint64_t seed) = 0; 38 | 39 | void *handle; 40 | if (!(handle = dlopen(*it, RTLD_NOW))) 41 | die("%s: couldn't load shared object file '%s'\n", argv0, *it); 42 | if (!(hash = dlsym(handle, "hash"))) 43 | die("%s: couldn't find the symbol 'hash' in '%s'\n", argv0, *it); 44 | 45 | uint64_t seed = trng_u64(0); 46 | uint64_t sum = 0; 47 | 48 | struct timespec beg, end; 49 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &beg); 50 | for (uint64_t i = 0; i < N; ++i) 51 | sum += hash(i, N-1, seed); 52 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); 53 | 54 | printf("%s took: %f ns/hash\n", *it, ((end.tv_sec - beg.tv_sec) * 1000000000 + (end.tv_nsec - beg.tv_nsec)) * 1.0 / N); 55 | } 56 | 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX = /usr/local 2 | 3 | HEADERS = arena-allocator.h arg.h bench.h random.h random-xmacros.h random-xoroshiro128-jump.h stretchy-buffer.h test.h 4 | 5 | all: 6 | 7 | install: 8 | mkdir -p "$(DESTDIR)$(PREFIX)/include/cauldron" 9 | cd cauldron && cp $(HEADERS) "$(DESTDIR)$(PREFIX)/include/cauldron" 10 | 11 | uninstall: 12 | -cd "$(DESTDIR)$(PREFIX)/include/cauldron" && rm $(HEADERS) 13 | -rmdir "$(DESTDIR)$(PREFIX)/include/cauldron" 14 | 15 | clean: 16 | make -C tools/random/ clean 17 | make -C tools/random/permute/ clean 18 | 19 | TIDY=clang-tidy -checks='cert-*,clang-analyzer-*,linuxkernel-*,misc-*, \ 20 | performance-*,portability-*,readability-*, \ 21 | -readability-braces-around-statements, \ 22 | -readability-isolate-declaration, \ 23 | -readability-magic-numbers, \ 24 | -readability-uppercase-literal-suffix, \ 25 | -cert-dcl37-c,-cert-dcl51-cpp' \ 26 | -header-filter='.*' --extra-arg-before=-I. \ 27 | --extra-arg=-std=c89 --extra-arg=-Dinline="" 28 | 29 | tidy: 30 | ${TIDY} cauldron/arg.h --extra-arg=-DARG_EXAMPLE 31 | ${TIDY} --extra-arg=-std=gnu99 cauldron/bench.h --extra-arg=-DBENCH_EXAMPLE 32 | ${TIDY} cauldron/test.h --extra-arg=-DTEST_EXAMPLE 33 | ${TIDY} test/arena-allocator.c 34 | ${TIDY} test/random/dist_normal.c 35 | ${TIDY} test/random/jump.c 36 | ${TIDY} test/random/shuf.c 37 | ${TIDY} test/stretchy-buffer/test.c 38 | -------------------------------------------------------------------------------- /test/random/jump.c: -------------------------------------------------------------------------------- 1 | #define RANDOM_H_IMPLEMENTATION 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #define MASK UINT16_MAX 10 | 11 | int 12 | main(void) 13 | { 14 | #define TEST(type, randomize, func, jump, args, n) do { \ 15 | size_t j; \ 16 | type a, b; \ 17 | randomize(&a); \ 18 | b = a; \ 19 | jump args; \ 20 | for (j = 0; j < n; ++j) \ 21 | func(&b); \ 22 | for (j = 0; j < 32; ++j) \ 23 | TEST_ASSERT(func(&a) == func(&b)); \ 24 | } while (0) 25 | 26 | size_t i; 27 | PRNG64RomuQuad prng64; 28 | prng64_romu_quad_randomize(&prng64); 29 | 30 | TEST_BEGIN(("prng64_pcg_jump")); 31 | for (i = 0; i < 25; ++i) { 32 | size_t n = prng64_romu_quad(&prng64) & MASK; 33 | TEST(PRNG32Pcg, prng32_pcg_randomize, prng32_pcg, 34 | prng32_pcg_jump, (&a, n), n); 35 | } 36 | TEST_END(); 37 | 38 | #if PRNG64_PCG_AVAILABLE 39 | TEST_BEGIN(("prng64_pcg_jump")); 40 | for (i = 0; i < 25; ++i) { 41 | uint64_t by[2] = { 0 }; 42 | by[1] = prng64_romu_quad(&prng64) & MASK; 43 | TEST(PRNG64Pcg, prng64_pcg_randomize, prng64_pcg, 44 | prng64_pcg_jump, (&a, by), by[1]); 45 | } 46 | TEST_END(); 47 | #endif 48 | 49 | TEST_BEGIN(("prng64_xoroshiro128_jump")); 50 | for (i = 7; i <= 20; ++i) { 51 | TEST(PRNG64Xoroshiro128, prng64_xoroshiro128_randomize, 52 | prng64_xoroshiro128ss, prng64_xoroshiro128_jump, 53 | (&a, prng64_xoroshiro128Jump2Pow[i]), UINT64_C(1) << i); 54 | } 55 | TEST_END(); 56 | /* The other xorshift prngs jump to far to test */ 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /tools/bithacks/unsigned-division-by-constant.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * The code is taken from the book "Hacker's Delight", by Henry S. Warren. 5 | * 6 | * This can transform an unsigned integer division by a constant into an 7 | * multiplication, a bitshift and potentially an addition. 8 | * Note that most compiler already implement this and good ones can infer even 9 | * better optimizations given the original division statement, instead of the 10 | * one generated by this program. 11 | * This is generally only needed when writing compilers or when working with a 12 | * non-optimizing compiler. 13 | */ 14 | 15 | int 16 | main(void) 17 | { 18 | unsigned long long div, c1, c2, c, q, r, delta; 19 | unsigned a, p, nbits; 20 | 21 | printf("divisor: "); 22 | scanf("%llu", &div); 23 | printf("with of type (in bits <= 64): "); 24 | scanf("%u", &nbits); 25 | 26 | c2 = (1ull << (nbits - 1)); 27 | c1 = c2 - 1; 28 | 29 | a = 0; 30 | p = nbits - 1; 31 | q = c1 / div; 32 | r = c1 - q * div; 33 | 34 | c = 0; 35 | do { 36 | c = (++p == nbits) ? 1 : 2 * c; 37 | if (r + 1 >= div - r) { 38 | if (q >= c1) 39 | a = 1; 40 | q = 2 * q + 1; 41 | r = 2 * r + 1 - div; 42 | } else { 43 | if (q >= c2) 44 | a = 1; 45 | q = 2 * q; 46 | r = 2 * r + 1; 47 | } 48 | delta = div - 1 - r; 49 | } while (p < 2 * nbits && c < delta); 50 | ++q; 51 | 52 | if (a) { 53 | printf("(uint%u_t)((x * UINT%u_C(%llu) + UINT%u_C(%llu)) >> %u)\n", 54 | nbits, nbits * 2, q, nbits * 2, q, p); 55 | } else { 56 | printf("(uint%u_t)((x * UINT%u_C(%llu)) >> %u)\n", 57 | nbits, nbits * 2, q, p); 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /ideas/fmt.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* printf.h */ 3 | 4 | #include 5 | 6 | #define FMT_BEGIN(fmt) do { \ 7 | char const *internal__fmt = fmt; \ 8 | internal__fmt += printf("%s", internal__fmt) + 1; 9 | 10 | 11 | #define FMT(name, args) \ 12 | (fmt_##name args, internal__fmt += printf("%s", internal__fmt) + 1) 13 | 14 | #define FMT_END } while (0) 15 | 16 | 17 | void fmt_uint(unsigned x) { printf("%u", x); } 18 | void fmt_float(float x) { printf("%f", x); } 19 | 20 | /******************************************************************************/ 21 | 22 | #include 23 | 24 | typedef struct { 25 | float x, y, z; 26 | } Vec3; 27 | 28 | void 29 | fmt_Vec3(Vec3 v) 30 | { 31 | FMT_BEGIN("{\0, \0, \0}") { 32 | FMT(float, (v.x)); 33 | FMT(float, (v.y)); 34 | FMT(float, (v.z)); 35 | } FMT_END; 36 | } 37 | 38 | void fmt_uint_base(unsigned x, int base, char const *digits) 39 | { 40 | char arr[sizeof x * CHAR_BIT]; 41 | char *s = arr + sizeof arr; 42 | do *--s = digits[x % base]; while ((x /= base) > 0); 43 | while (*s) 44 | putchar(*s++); 45 | } 46 | 47 | int 48 | main(void) 49 | { 50 | { 51 | float a = 3.141592, b = 2.718281828; 52 | 53 | FMT_BEGIN("a + b = \0 + \0 = \0\n") { 54 | FMT(float, (a)); 55 | FMT(float, (b)); 56 | FMT(float, (a + b)); 57 | } FMT_END; 58 | } 59 | 60 | { 61 | Vec3 a = { 1.0f/3.0f, -69.69f, 189 }; 62 | Vec3 b = { 3.141592f, 2.718281828f, 420.69f }; 63 | unsigned x = 0xdeadbeef; 64 | 65 | FMT_BEGIN("x = \0 = 0x\0 = 0b\0\na = \0\nb = \0\n") { 66 | FMT(uint, (x)); 67 | FMT(uint_base, ((unsigned)x, 16, "0123456789abcdef")); 68 | FMT(uint_base, ((unsigned)x, 2, "01")); 69 | FMT(Vec3, (a)); 70 | FMT(Vec3, (b)); 71 | } FMT_END; 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /tools/random/testu01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | struct Battery { 9 | void (*f)(unif01_Gen *gen); 10 | char *name, *desc; 11 | } batteries[] = { 12 | { bbattery_SmallCrush, "SmallCrush", "takes ~1m" }, 13 | { bbattery_Crush, "Crush", "takes ~1h" }, 14 | { bbattery_BigCrush, "BigCrush", "takes ~8h" }, 15 | }; 16 | 17 | void usage(char *argv0) 18 | { 19 | size_t i; 20 | printf("usage: %s BATTERY\n", argv0); 21 | puts("Reads data stream from standart input."); 22 | puts("Batteries:"); 23 | for (i = 0; i < sizeof batteries / sizeof *batteries; ++i) 24 | printf("\t'%s': %s\n", batteries[i].name, batteries[i].desc); 25 | puts("Execution time tested on an AMD Athlon 64 4000+ Processor"); 26 | puts("with a clock speed of 2400 MHz running Linux."); 27 | } 28 | 29 | uint32_t next(void) 30 | { 31 | uint32_t res; 32 | fread(&res, sizeof res, 1, stdin); 33 | return res; 34 | } 35 | 36 | int main(int argc, char **argv) 37 | { 38 | char **it = argv + 1; 39 | 40 | if (!*it || argc <= 1) { 41 | usage(argv[0]); 42 | return EXIT_FAILURE; 43 | } 44 | 45 | (void)freopen(0, "rb", stdin); 46 | 47 | unif01_Gen* gen = unif01_CreateExternGenBits("stdin", next); 48 | 49 | do { 50 | size_t i; 51 | for (i = 0; i < sizeof batteries / sizeof *batteries; ++i) { 52 | if (strcmp(*it, batteries[i].name) == 0) { 53 | batteries[i].f(gen); 54 | fflush(stdout); 55 | break; 56 | } 57 | } 58 | if (i == sizeof batteries / sizeof *batteries) { 59 | fprintf(stderr, "%s error: Unknown test battery '%s'\n\n", 60 | argv[0], *it); 61 | usage(argv[0]); 62 | return EXIT_FAILURE; 63 | } 64 | } while (*++it); 65 | 66 | unif01_DeleteExternGenBits(gen); 67 | return EXIT_SUCCESS; 68 | } 69 | -------------------------------------------------------------------------------- /tools/random/permute/plot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | printbest=false 4 | gpeval="set terminal wxt persist;" 5 | cmd="./evalpow2" 6 | while getopts '0bcn:q:o:s:S:' OPTION 7 | do 8 | case $OPTION in 9 | 0) cmd="${cmd} -0" 10 | ;; 11 | b) printbest=true 12 | ;; 13 | c) cmd="${cmd} -c" 14 | ;; 15 | n) cmd="${cmd} -n $OPTARG" 16 | ;; 17 | o) gpeval="set terminal ${OPTARG##*.}; set output '$OPTARG';" 18 | #o) gpeval="set terminal ${OPTARG##*.} size 400,300; set output '$OPTARG';" 19 | ;; 20 | q) cmd="${cmd} -q $OPTARG" 21 | ;; 22 | s) cmd="${cmd} -s $OPTARG" 23 | ;; 24 | S) cmd="${cmd} -S $OPTARG" 25 | ;; 26 | ?) printf "Usage: %s: [-c] [-n bits] [-q quality] [-s start] [-S stop] files" $(basename "$0") >&2 27 | exit 2 28 | ;; 29 | esac 30 | done 31 | 32 | gpeval="${gpeval}set title \"$0 ${@:3:$(($OPTIND - 3))}\" offset 0,-0.5;" 33 | shift $(($OPTIND - 1)) 34 | gpeval="${gpeval}filenames=\"" 35 | 36 | 37 | DIR=`mktemp -d` 38 | trap '{ rm -rf -- "$DIR"; }' EXIT 39 | 40 | if [ $printbest ] 41 | then 42 | eval "$cmd -o $DIR/best.so.csv -b" 43 | gpeval="${gpeval}$DIR/best.so.csv " 44 | fi 45 | 46 | i=0 47 | for so in "$@"; do 48 | csv="$DIR/$(basename $so).csv" 49 | eval "$cmd -o $csv -l $so" 50 | i=$((i+1)) 51 | gpeval="${gpeval}$csv " 52 | done 53 | gpeval="${gpeval}\"" 54 | 55 | 56 | cat < $DIR/plot.gp 57 | set grid lt 1 lc rgb "grey" lw 0.5 58 | 59 | set datafile separator ',' 60 | set logscale y 61 | 62 | if (1) { 63 | set xlabel "bits" 64 | set ylabel "bias" 65 | } else { 66 | set xlabel "bits" offset 0,1 67 | set ylabel "bias" offset 4,0 68 | set key spacing 0.6 69 | set yrange[-1:5000] 70 | 71 | set tmargin 2 72 | set lmargin 5 73 | set bmargin 2 74 | } 75 | 76 | 77 | plot for [file in filenames] file u 1:2 w l lw 2 t system(sprintf("basename %s .so.csv",file)) 78 | EOF 79 | 80 | gnuplot -e "$gpeval" $DIR/plot.gp 81 | 82 | -------------------------------------------------------------------------------- /test/stretchy-buffer/test.c: -------------------------------------------------------------------------------- 1 | #define RANDOM_H_IMPLEMENTATION 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define EQ(a,b) (a == b) 12 | #define RAND(x) (trng_write(&x, sizeof x), x) 13 | 14 | #define FUNC test_char 15 | #define NAME "Sb(char)" 16 | #define T char 17 | #include "xtest.h" 18 | #define FUNC test_short 19 | #define NAME "Sb(short)" 20 | #define T short 21 | #include "xtest.h" 22 | #define FUNC test_int 23 | #define NAME "Sb(int)" 24 | #define T int 25 | #include "xtest.h" 26 | #define FUNC test_long 27 | #define NAME "Sb(long)" 28 | #define T long 29 | #include "xtest.h" 30 | 31 | #undef RAND 32 | #define RAND(x) (x = dist_uniform(trng_u64(0))) 33 | 34 | #define FUNC test_float 35 | #define NAME "Sb(float)" 36 | #define T float 37 | #include "xtest.h" 38 | #define FUNC test_double 39 | #define NAME "Sb(double)" 40 | #define T double 41 | #include "xtest.h" 42 | #define FUNC test_ldouble 43 | #define NAME "Sb(long double)" 44 | #define T long double 45 | #include "xtest.h" 46 | 47 | #undef RAND 48 | #define RAND(x) (trng_write(&x, sizeof x), x) 49 | 50 | struct S1 { char c[42]; size_t x, y; }; 51 | #define FUNC test_s1 52 | #define NAME "Sb(struct { char c[42]; size_t a, b; })" 53 | #define T struct S1 54 | #undef EQ 55 | #define EQ(a,b) (memcmp(&a.c, &b.c, sizeof a.c) == 0 && a.x == b.x && a.y == b.y) 56 | #include "xtest.h" 57 | 58 | union S2 { struct { char x,y,z; } s; int u; }; 59 | #define FUNC test_s2 60 | #define NAME "Sb(union { struct { char x,y,z; } s; int u; })" 61 | #define T union S2 62 | #undef EQ 63 | #define EQ(a,b) (a.s.x == b.s.x && a.s.y == b.s.y && a.s.z == b.s.z) 64 | #include "xtest.h" 65 | 66 | 67 | int 68 | main(void) 69 | { 70 | test_char(); 71 | test_short(); 72 | test_int(); 73 | test_long(); 74 | test_float(); 75 | test_double(); 76 | test_ldouble(); 77 | test_s1(); 78 | test_s2(); 79 | return 0; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cauldron 2 | 3 | A collection of single-file C libraries and tools with the goal to be portable and modifiable. 4 | 5 | [![Tests](https://github.com/camel-cdr/cauldron/workflows/Tests/badge.svg)](https://github.com/camel-cdr/cauldron/actions?workflow=Tests) 6 | 7 | 8 | ## Libraries 9 | 10 | library | description | language 11 | :------- | :----------- | :--------: 12 | **[arena-allocator.h](cauldron/arena-allocator.h)** | drop in arena allocator | C 13 | **[arg.h](cauldron/arg.h)** | POSIX compliant argument parser based on plan9's arg(3) | C/C++ 14 | **[bench.h](cauldron/bench.h)** | micro benchmarking framework | C/C++ 15 | **[random.h](cauldron/random.h)** | literate random number library and tutorial [(related talk)](https://youtu.be/VHJUlRiRDCY) | C/C++ 16 | **[stretchy-buffer.h](cauldron/stretchy-buffer.h)** | generic dynamic array | C 17 | **[test.h](cauldron/test.h)** | minimal unit testing | C/C++ 18 | 19 | ## Tools 20 | 21 | ### Bithacks 22 | * [unsigned division by constants](tools/bithacks/unsigned-division-by-constant.c) 23 | 24 | ### Random 25 | * [RNG benchmark](tools/random/bench.c) 26 | * RNG cli tools: [rng](tools/random/rng.c), [dist](tools/random/dist.c) 27 | * [generate ziggurat constants](tools/random/ziggurat-constants.c) 28 | * [Improving Andrew Kensler's permute(): A function for stateless, constant-time pseudorandom-order array iteration](tools/random/permute) 29 | 30 | ## Similar projects 31 | * [klib](https://github.com/attractivechaos/klib) 32 | * [portable-snippets](https://github.com/nemequ/portable-snippets) 33 | * [stb](https://github.com/nothings/stb) 34 | 35 | ## Licensing 36 | For all files without a integrated license [LICENSE](LICENSE) applies. 37 | -------------------------------------------------------------------------------- /test/random/dist_uniform.c: -------------------------------------------------------------------------------- 1 | #define RANDOM_H_IMPLEMENTATION 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define NUM_RUNS 8 9 | #define RUN_LENGTH_MASK 1023 10 | #define RUN_TIME_OUT (1024*1024*8) 11 | 12 | #define TEST_FULL_RANGE(name, T, init, next, inc) \ 13 | TEST_BEGIN((name " full range")); \ 14 | for (i = 0; i < NUM_RUNS; ++i) { \ 15 | T beg, cur, end; \ 16 | init; \ 17 | for (i = 0; i < RUN_TIME_OUT && cur < end; ++i) \ 18 | if (next == cur) \ 19 | inc; \ 20 | TEST_ASSERT(i < RUN_TIME_OUT); \ 21 | } \ 22 | TEST_END() 23 | 24 | static PRNG32RomuQuad prng32; 25 | static PRNG64RomuQuad prng64; 26 | 27 | static void 28 | random_rangef(float *beg, float *cur, float *end) 29 | { 30 | union { uint32_t i; float f; } u; 31 | uint32_t n; 32 | float e; 33 | do u.i = prng32_romu_quad(&prng32); while (!isfinite(u.f)); 34 | *beg = *cur = e = u.f; 35 | n = prng32_romu_quad(&prng32) & RUN_LENGTH_MASK; 36 | while (n--) e = nextafterf(e, FLT_MAX); 37 | *end = e; 38 | } 39 | 40 | static void 41 | random_range(double *beg, double *cur, double *end) 42 | { 43 | union { uint64_t i; double f; } u; 44 | uint64_t n; 45 | double e; 46 | do u.i = prng64_romu_quad(&prng64); while (!isfinite(u.f)); 47 | *beg = *cur = e = u.f; 48 | n = prng32_romu_quad(&prng32) & RUN_LENGTH_MASK; 49 | while (n--) e = nextafter(e, DBL_MAX); 50 | *end = e; 51 | } 52 | 53 | int 54 | main(void) 55 | { 56 | size_t i; 57 | prng32_romu_quad_randomize(&prng32); 58 | prng64_romu_quad_randomize(&prng64); 59 | 60 | TEST_FULL_RANGE( 61 | "dist_uniform_u32", uint32_t, 62 | (beg = cur = 0, 63 | end = prng32_romu_quad(&prng32) & RUN_LENGTH_MASK), 64 | dist_uniform_u32(end, prng32_romu_quad, &prng32), ++cur); 65 | 66 | TEST_FULL_RANGE( 67 | "dist_uniform_u64", uint64_t, 68 | (beg = cur = 0, 69 | end = prng64_romu_quad(&prng64) & RUN_LENGTH_MASK), 70 | dist_uniform_u64(end, prng64_romu_quad, &prng64), ++cur); 71 | 72 | TEST_FULL_RANGE( 73 | "dist_uniformf", float, 74 | random_rangef(&beg, &cur, &end), 75 | dist_uniformf_dense(beg, end, prng32_romu_quad, &prng32), 76 | cur = nextafterf(cur, FLT_MAX)); 77 | 78 | TEST_FULL_RANGE( 79 | "dist_uniform", double, 80 | random_range(&beg, &cur, &end), 81 | dist_uniform_dense(beg, end, prng64_romu_quad, &prng64), 82 | cur = nextafter(cur, DBL_MAX)); 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /tools/random/ziggurat-constants.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define M_SQRTPI_OVER_SQRT2 1.253314137315500251207882642405522627L 6 | #define M_1_OVER_SQRT2 0.707106781186547524400844362104849039L 7 | 8 | #define ziggurat_f(x) expl(-0.5 * x * x) 9 | #define ziggurat_f_inv(y) sqrtl(-2 * logl(y)) 10 | #define ziggurat_f_int_x_to_inf(x) \ 11 | -(M_SQRTPI_OVER_SQRT2 * (erfl(x * M_1_OVER_SQRT2) - 1)) 12 | 13 | int 14 | main(void) 15 | { 16 | unsigned count = 0; 17 | printf("#define ZIGGURAT_COUNT "); 18 | scanf("%u", &count); 19 | 20 | long double min = 0, max = 10, pmin, pmax; 21 | long double area, R; 22 | do { 23 | int tobig = 0; 24 | 25 | pmin = min; 26 | pmax = max; 27 | 28 | R = 0.5 * (min + max); 29 | long double x = R; 30 | area = R * ziggurat_f(R) + ziggurat_f_int_x_to_inf(R); 31 | for (unsigned i = 1; i < count && !tobig; i++) { 32 | x = area / x + ziggurat_f(x); 33 | if (x > 1) tobig = 1; 34 | else x = ziggurat_f_inv(x); 35 | } 36 | if (tobig) 37 | min = R; 38 | else 39 | max = R; 40 | } while (pmin < R && R < pmax); 41 | 42 | printf("#define ZIGGURAT_R %.*Lg\n", DECIMAL_DIG, R); 43 | printf("#define ZIGGURAT_AREA %.*Lg\n", DECIMAL_DIG, area); 44 | } 45 | 46 | /* 47 | * Copyright (c) 2021 Olaf Berstein 48 | * Permission is hereby granted, free of charge, to any person obtaining a copy 49 | * of this software and associated documentation files (the "Software"), to deal 50 | * in the Software without restriction, including without limitation the rights 51 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 52 | * copies of the Software, and to permit persons to whom the Software is 53 | * furnished to do so, subject to the following conditions: 54 | * The above copyright notice and this permission notice shall be included in 55 | * all copies or substantial portions of the Software. 56 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 57 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 58 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 59 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 60 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 61 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 62 | * SOFTWARE. 63 | */ 64 | 65 | -------------------------------------------------------------------------------- /cauldron/test.h: -------------------------------------------------------------------------------- 1 | /* test.h -- minimal unit testing 2 | * Olaf Bernstein 3 | * Distributed under the MIT license, see license at the end of the file. 4 | * New versions available at https://github.com/camel-cdr/cauldron 5 | */ 6 | 7 | #ifndef TEST_H_INCLUDED 8 | 9 | static unsigned test__nasserts, test__nfailures; 10 | 11 | #define TEST_BEGIN(msg) \ 12 | test__nasserts = test__nfailures = 0; \ 13 | fputs("Testing ", stdout); \ 14 | printf msg; \ 15 | fputs(" ...", stdout); 16 | 17 | #define TEST_END() \ 18 | if (test__nfailures == 0) { \ 19 | puts("PASSED"); \ 20 | } else { \ 21 | printf("\t-> %u assertions, %u failures\n", \ 22 | test__nasserts, test__nfailures); \ 23 | exit(EXIT_FAILURE); \ 24 | } 25 | 26 | #define TEST_ASSERT(cnd) TEST_ASSERT_MSG((cnd), (#cnd)) 27 | #define TEST_ASSERT_MSG(cnd, msg) \ 28 | do { \ 29 | if (!(cnd)) { \ 30 | if (test__nfailures++ == 0) puts("FAILED"); \ 31 | printf("\t%s:%d:\n", __FILE__, __LINE__); \ 32 | printf msg; \ 33 | putchar('\n'); \ 34 | } \ 35 | ++test__nasserts; \ 36 | } while (0) 37 | 38 | #define TEST_H_INCLUDED 39 | #endif 40 | 41 | /* 42 | * Example: 43 | */ 44 | 45 | #ifdef TEST_EXAMPLE 46 | 47 | #include 48 | #include 49 | 50 | 51 | int 52 | main(void) 53 | { 54 | int i; 55 | 56 | TEST_BEGIN(("Testing a")); 57 | TEST_ASSERT(4 == 4); 58 | #if 0 59 | TEST_ASSERT(3.141592 == 2.718281828); 60 | TEST_ASSERT(42 == 69); 61 | #endif 62 | TEST_ASSERT(3 == 1+2); 63 | TEST_END(); 64 | 65 | for (i = 0; i < 4; ++i) { 66 | TEST_BEGIN(("Testing b%d", i)); 67 | TEST_ASSERT("test"[i] != 'a'); 68 | TEST_END(); 69 | } 70 | 71 | return 0; 72 | } 73 | 74 | #endif /* TEST_EXAMPLE */ 75 | 76 | /* 77 | * Copyright (c) 2022 Olaf Berstein 78 | * Permission is hereby granted, free of charge, to any person obtaining a copy 79 | * of this software and associated documentation files (the "Software"), to deal 80 | * in the Software without restriction, including without limitation the rights 81 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 82 | * copies of the Software, and to permit persons to whom the Software is 83 | * furnished to do so, subject to the following conditions: 84 | * The above copyright notice and this permission notice shall be included in 85 | * all copies or substantial portions of the Software. 86 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 87 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 88 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 89 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 90 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 91 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 92 | * SOFTWARE. 93 | */ 94 | 95 | -------------------------------------------------------------------------------- /tools/random/rng.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define RANDOM_H_IMPLEMENTATION 6 | #include 7 | 8 | #include "extra.h" 9 | 10 | /* 11 | * Example: 12 | * ./rng | ./testu01 SmallCrush 13 | * ./rng | ./RNG_test stdin 14 | */ 15 | 16 | #define BUFSIZE (1024*1024) 17 | void *buffer; 18 | void *bufferend; 19 | 20 | #define RANDOM_X16(type, func, rand) \ 21 | MAKE_RNG(func, type, rand, 16) 22 | #define RANDOM_X32(type, func, rand) \ 23 | MAKE_RNG(func, type, rand, 32) 24 | #define RANDOM_X64(type, func, rand) \ 25 | MAKE_RNG(func, type, rand, 64) 26 | 27 | #define MAKE_RNG(func, type, rand, n) \ 28 | static void \ 29 | run_##func(void) \ 30 | { \ 31 | type rng; \ 32 | rand(&rng); \ 33 | while (1) { \ 34 | uint##n##_t *p = buffer; \ 35 | while ((void*)p < bufferend) \ 36 | *p++ = func(&rng); \ 37 | fwrite(buffer, 1, BUFSIZE, stdout); \ 38 | } \ 39 | } 40 | 41 | #include 42 | #include "extra-xmacros.h" 43 | #undef MAKE_RNG 44 | 45 | 46 | static void 47 | run_trng_write(void) 48 | { 49 | while (1) { 50 | trng_write(buffer, BUFSIZE); 51 | fwrite(buffer, 1, BUFSIZE, stdout); 52 | } 53 | } 54 | 55 | static struct { 56 | char *name; 57 | void (*rng)(void); 58 | } rngs[] = { 59 | #undef RANDOM_X16 60 | #undef RANDOM_X32 61 | #undef RANDOM_X64 62 | #define RANDOM_X16(type, func, rand) { #func, run_##func }, 63 | #define RANDOM_X32(type, func, rand) 64 | #define RANDOM_X64(type, func, rand) 65 | #include 66 | #include "extra-xmacros.h" 67 | #undef RANDOM_X16 68 | #undef RANDOM_X32 69 | #undef RANDOM_X64 70 | #define RANDOM_X16(type, func, rand) 71 | #define RANDOM_X32(type, func, rand) { #func, run_##func }, 72 | #define RANDOM_X64(type, func, rand) 73 | #include 74 | #include "extra-xmacros.h" 75 | #undef RANDOM_X16 76 | #undef RANDOM_X32 77 | #undef RANDOM_X64 78 | #define RANDOM_X16(type, func, rand) 79 | #define RANDOM_X32(type, func, rand) 80 | #define RANDOM_X64(type, func, rand) { #func, run_##func }, 81 | #include 82 | #include "extra-xmacros.h" 83 | }; 84 | 85 | static void list(void) 86 | { 87 | size_t i; 88 | for (i = 0; i < sizeof rngs / sizeof *rngs; ++i) 89 | puts(rngs[i].name); 90 | } 91 | 92 | int 93 | main(int argc, char **argv) 94 | { 95 | size_t i; 96 | char *name = argv[1]; 97 | 98 | (void)argc; 99 | 100 | buffer = malloc(BUFSIZE); 101 | bufferend = (void*)((char*)buffer + BUFSIZE); 102 | 103 | if (!name) { 104 | list(); 105 | return EXIT_FAILURE; 106 | } 107 | 108 | for (i = 0; i < sizeof rngs / sizeof *rngs; ++ i) { 109 | if (strcmp(name, rngs[i].name) == 0) { 110 | rngs[i].rng(); 111 | return EXIT_SUCCESS; 112 | } 113 | } 114 | list(); 115 | return EXIT_FAILURE; 116 | } 117 | -------------------------------------------------------------------------------- /test/random/shuf.c: -------------------------------------------------------------------------------- 1 | #define RANDOM_H_IMPLEMENTATION 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX_SIZE (1024) 10 | #define COUNT (128) 11 | 12 | #define ALPHA (0.5) 13 | 14 | int 15 | comp_size_t(void const *lhs, void const *rhs) 16 | { 17 | size_t const *l = (size_t const*)lhs, *r = (size_t const*)rhs; 18 | return *l - *r; 19 | } 20 | 21 | size_t 22 | validate_shuffle(size_t *arr, size_t const *sorted, size_t size) 23 | { 24 | size_t i, cnt; 25 | /* we'd expect to get on average 1 element with the same position */ 26 | for (i = cnt = 0; i < size; ++i) 27 | cnt += (arr[i] == sorted[i]); 28 | 29 | /* make sure no element is lost */ 30 | qsort(arr, size, sizeof *arr, comp_size_t); 31 | for (i = 0; i < size; ++i) { 32 | TEST_ASSERT(arr[i] == sorted[i]); 33 | } 34 | return cnt; 35 | } 36 | 37 | int 38 | main(void) 39 | { 40 | size_t i, j, cnt, size; 41 | PRNG32RomuQuad prng32; 42 | PRNG64RomuQuad prng64; 43 | size_t *arr = (size_t*)malloc(MAX_SIZE * sizeof *arr); 44 | size_t *sorted = (size_t*)malloc(MAX_SIZE * sizeof *arr); 45 | prng32_romu_quad_randomize(&prng32); 46 | prng64_romu_quad_randomize(&prng64); 47 | 48 | for (i = 0; i < MAX_SIZE; ++i) 49 | sorted[i] = arr[i] = i; 50 | 51 | TEST_BEGIN(("shuf32_arr")); 52 | for (cnt = i = 0; i < COUNT; ++i) { 53 | size = dist_uniform_u32(MAX_SIZE-2, prng32_romu_quad, &prng32)+2; 54 | shuf32_arr(arr, size, sizeof *arr, prng32_romu_quad, &prng32); 55 | cnt += validate_shuffle(arr, sorted, size); 56 | } 57 | TEST_ASSERT((float)cnt / COUNT - 1.0 < ALPHA); 58 | TEST_END(); 59 | 60 | TEST_BEGIN(("shuf64_arr")); 61 | for (cnt = i = 0; i < COUNT; ++i) { 62 | size = dist_uniform_u64(MAX_SIZE-2, prng64_romu_quad, &prng64)+2; 63 | shuf64_arr(arr, size, sizeof *arr, prng64_romu_quad, &prng64); 64 | cnt += validate_shuffle(arr, sorted, size); 65 | } 66 | TEST_ASSERT((float)cnt / COUNT - 1.0 < ALPHA); 67 | TEST_END(); 68 | 69 | TEST_BEGIN(("shuf_weyl")) 70 | for (cnt = i = 0; i < COUNT; ++i) { 71 | ShufWeyl weyl; 72 | size = dist_uniform_u64(MAX_SIZE-2, prng64_romu_quad, &prng64)+2; 73 | shuf_weyl_randomize(&weyl, size); 74 | 75 | for (i = 0; i < size; ++i) { 76 | j = shuf_weyl(&weyl); 77 | TEST_ASSERT(j < size); 78 | arr[j] = sorted[i]; 79 | } 80 | 81 | cnt += validate_shuffle(arr, sorted, size); 82 | } 83 | TEST_ASSERT((float)cnt / COUNT - 1.0 < ALPHA); 84 | TEST_END(); 85 | 86 | TEST_BEGIN(("shuf_lcg")) 87 | for (cnt = i = 0; i < COUNT; ++i) { 88 | ShufLcg lcg; 89 | size = dist_uniform_u64(MAX_SIZE-2, prng64_romu_quad, &prng64)+2; 90 | shuf_lcg_randomize(&lcg, size); 91 | 92 | for (i = 0; i < size; ++i) { 93 | j = shuf_lcg(&lcg); 94 | TEST_ASSERT(j < size); 95 | arr[j] = sorted[i]; 96 | } 97 | 98 | cnt += validate_shuffle(arr, sorted, size); 99 | } 100 | TEST_ASSERT((float)cnt / COUNT - 1.0 < ALPHA); 101 | TEST_END(); 102 | 103 | free(sorted); 104 | free(arr); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /tools/random/permute/rng-shuffle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #define RANDOM_H_IMPLEMENTATION 9 | #include 10 | 11 | 12 | #include 13 | #include 14 | 15 | 16 | #define BUFSIZE (1uLL << 30) 17 | 18 | PRNG64RomuQuad *prngs; 19 | 20 | void 21 | gen_cnt(uint64_t cnt[256], uint64_t count) 22 | { 23 | uint64_t i; 24 | #pragma omp parallel 25 | { 26 | PRNG64RomuQuad *r = prngs + omp_get_thread_num(); 27 | #pragma omp for reduction(+:cnt[:256]) 28 | for (i = 0; i < count; ++i) 29 | ++cnt[prng64_romu_quad(r) & 0xFF]; 30 | } 31 | } 32 | 33 | static void 34 | die(char *fmt, ...) 35 | { 36 | va_list args; 37 | va_start(args, fmt); 38 | vfprintf(stderr, fmt, args); 39 | va_end(args); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | static void 44 | usage(char *argv0) 45 | { 46 | printf("usage: %s N SHARED_OBJECT_FILE \n", argv0); 47 | puts("Outputs 2^N bytes per seed from the lowest byte of the output from"); 48 | puts("the following hash function, which is loaded from the SHARED_OBJECT_FILE."); 49 | puts("uint64_t hash(uint64_t i, uint64_t mask, uint64_t seed)"); 50 | } 51 | 52 | int 53 | main(int argc, char **argv) 54 | { 55 | uint64_t count = 0; 56 | uint8_t *buf; 57 | uint64_t (*hash)(uint64_t i, uint64_t mask, uint64_t seed); 58 | 59 | if (argc != 3 || !argv[2]) { 60 | usage(argv[0]); 61 | return EXIT_FAILURE; 62 | } 63 | 64 | { 65 | void *handle; 66 | int c = atoi(argv[1]); 67 | if (c < 1 || c > 63) 68 | die("%s: N out of range, expected 1 to 63, got '%d'\n", 69 | argv[0], c); 70 | count = UINT64_C(1) << c; 71 | 72 | if (!(handle = dlopen(argv[2], RTLD_NOW))) 73 | die("%s: couldn't load shared object file '%s'\n", argv[0], argv[2]); 74 | if (!(hash = dlsym(handle, "hash"))) 75 | die("%s: couldn't find the symbol 'hash' in '%s'\n", argv[0], argv[2]); 76 | } 77 | 78 | buf = malloc(BUFSIZE); 79 | prngs = malloc(sizeof *prngs * omp_get_max_threads()); 80 | if (!buf || !prngs) 81 | die("%s: malloc failed\n", argv[0]); 82 | 83 | for (int i = 0; i < omp_get_max_threads(); ++i) 84 | prng64_romu_quad_randomize(prngs + i); 85 | 86 | while (1) { 87 | uint64_t cnt[256] = { 0 }; 88 | uint64_t n = count; 89 | uint64_t mask = n-1; 90 | uint64_t seed = trng_u64(0); 91 | 92 | gen_cnt(cnt, n); 93 | for (int i = 1; i < 256; ++i) 94 | cnt[i] += cnt[i-1]; 95 | cnt[255] = n; 96 | 97 | for (; n > BUFSIZE; n -= BUFSIZE) { 98 | #pragma omp parallel for 99 | for (uint64_t i = 0; i < BUFSIZE; ++i) { 100 | uint64_t x = hash(i, mask, seed); 101 | for (int j = 0; j < 256; ++j) { 102 | if (x < cnt[j]) { 103 | buf[i] = j; 104 | break; 105 | } 106 | } 107 | } 108 | fwrite(buf, BUFSIZE, 1, stdout); 109 | } 110 | 111 | #pragma omp parallel for 112 | for (uint64_t i = 0; i < n; ++i) { 113 | uint64_t x = hash(i, mask, seed); 114 | for (int j = 0; j < 256; ++j) { 115 | if (x < cnt[j]) { 116 | buf[i] = j; 117 | break; 118 | } 119 | } 120 | } 121 | fwrite(buf, n, 1, stdout); 122 | } 123 | 124 | return EXIT_SUCCESS; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /test/random/dist_uniform_dense.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define RANDOM_H_IMPLEMENTATION 7 | #include 8 | #include 9 | 10 | /* 11 | * Make sure that you don't use -ffast-math or -Ofast when compiling this, 12 | * because that might disable denormals, which this test for. 13 | */ 14 | 15 | #define NRANGES 8 16 | #define MAX_TESTS (1024*1024*2) 17 | #define ALPHA 100.0 18 | 19 | #define ARRLEN(a) (sizeof (a) / sizeof *(a)) 20 | 21 | static float float_tests[][4] = { 22 | { 0, 1, 2, 3 }, 23 | { -2, -1, 1, 2 }, 24 | { -5, -4, -2, -1 }, 25 | { 9e-45f, 4e-41f, 2e-39f, 1.1e-38f }, /* denormals */ 26 | { 1e-38f, 1.2e-38f, 1.4e-38f, 2e-38f }, /* denormal boundary */ 27 | { 1e-40f, 3e-38f, 3e-35f, 3e-33f }, 28 | }; 29 | 30 | static double double_tests[][4] = { 31 | { 0, 1, 2, 3 }, 32 | { -2, -1, 1, 2 }, 33 | { -5, -4, -2, -1 }, 34 | { 9e-320, 9e-317, 9e-311, 1.1e-310 }, /* denormals */ 35 | { 9e-317, 9e-314, 9e-310, 2e-308 }, /* denormal boundary */ 36 | { 9e-300, 9e-294, 9e-292, 2e-288 }, 37 | }; 38 | 39 | #define MAKE_TEST(name, type, next) \ 40 | TEST_BEGIN((name)); \ 41 | for (i = 0; i < NRANGES + ARRLEN(float_tests); ++i) { \ 42 | double expected, ntests, stddev; \ 43 | type tmp, r[4]; /* f1, s1, s2, f2 */ \ 44 | size_t cnt = 0; \ 45 | \ 46 | if (i < ARRLEN(float_tests)) { \ 47 | for (j = 0; j < 4; ++j) \ 48 | r[j] = type##_tests[i][j]; \ 49 | } else while (1) { type##fallback: \ 50 | trng_write(r, sizeof r); \ 51 | if (!isfinite(r[0]) || !isfinite(r[1]) || \ 52 | !isfinite(r[2]) || !isfinite(r[3])) \ 53 | continue; \ 54 | /* sorting network for r */ \ 55 | if (r[0] > r[2]) tmp = r[0], r[0] = r[2], r[2] = tmp; \ 56 | if (r[1] > r[3]) tmp = r[1], r[1] = r[3], r[3] = tmp; \ 57 | if (r[0] > r[1]) tmp = r[0], r[0] = r[1], r[1] = tmp; \ 58 | if (r[2] > r[3]) tmp = r[2], r[2] = r[3], r[3] = tmp; \ 59 | if (r[1] > r[2]) tmp = r[1], r[1] = r[2], r[2] = tmp; \ 60 | if (r[0] != r[3] && r[1] != r[2]) \ 61 | break; \ 62 | } \ 63 | \ 64 | expected = (1.0*r[2]-r[1]) / (1.0*r[3]-r[0]); \ 65 | ntests = ALPHA / expected; \ 66 | if (ntests > MAX_TESTS) \ 67 | goto type##fallback; \ 68 | \ 69 | for (j = 0; j < ntests; ++j) { \ 70 | type x = next; \ 71 | if (x >= r[1] && x <= r[2]) \ 72 | ++cnt; \ 73 | } \ 74 | \ 75 | stddev = sqrt(ntests * expected * (1.0 - expected)); \ 76 | /* printf("%g %g %g %g | %g %g | %g %g\n", 77 | r[0], r[1], r[2], r[3], 78 | expected, ntests, stddev * 5, fabs(ALPHA - cnt)); */ \ 79 | /* fail with a probability of 5 sigma */ \ 80 | TEST_ASSERT(5 * stddev > fabs(ALPHA - cnt)); \ 81 | } \ 82 | TEST_END(); 83 | 84 | int 85 | main(void) 86 | { 87 | size_t i, j; 88 | PRNG32RomuQuad prng32; 89 | PRNG64RomuDuo prng64; 90 | prng32_romu_quad_randomize(&prng32); 91 | prng64_romu_duo_randomize(&prng64); 92 | 93 | MAKE_TEST("dist_uniformf_dense", float, 94 | dist_uniformf_dense(r[0], r[3], prng32_romu_quad, &prng32)); 95 | MAKE_TEST("dist_uniform_dense", double, 96 | dist_uniform_dense(r[0], r[3], prng64_romu_duo_jr, &prng64)); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /tools/random/bench.c: -------------------------------------------------------------------------------- 1 | #define RANDOM_H_IMPLEMENTATION 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | #include "extra.h" 11 | 12 | #define COUNT (1024*512*2ull) 13 | #define SAMPLES (64*2) 14 | 15 | #define BENCH_RNG(name, type, init, next, ftype, max) \ 16 | do { \ 17 | type rng; \ 18 | init; \ 19 | BENCH(name, 8, SAMPLES) { \ 20 | ftype x, y; \ 21 | size_t i, c; \ 22 | double pi; \ 23 | for (i = c = 0; i < COUNT; ++i) { \ 24 | x = next * (ftype)1.0 / max; \ 25 | y = next * (ftype)1.0 / max; \ 26 | if (x*x + y*y <= (ftype)1.0) \ 27 | ++c; \ 28 | } \ 29 | pi = (double)c / COUNT * 4.0; \ 30 | BENCH_VOLATILE(pi); \ 31 | } \ 32 | } while (0); 33 | 34 | static void 35 | bench_rng_16(void) 36 | { 37 | puts("16-bit PRNGs:"); 38 | #define RANDOM_X16(type, func, rnd) \ 39 | BENCH_RNG(#func, type, rnd(&rng), func(&rng), float, UINT16_MAX) 40 | #define RANDOM_X32(type, func, rnd) 41 | #define RANDOM_X64(type, func, rnd) 42 | #include 43 | #include "extra-xmacros.h" 44 | #undef RANDOM_X16 45 | #undef RANDOM_X32 46 | #undef RANDOM_X64 47 | bench_done(); 48 | putchar('\n'); 49 | } 50 | 51 | static void 52 | bench_rng_32(void) 53 | { 54 | puts("32-bit PRNGs"); 55 | #define RANDOM_X16(type, func, rnd) 56 | #define RANDOM_X32(type, func, rnd) \ 57 | BENCH_RNG(#func, type, rnd(&rng), func(&rng), float, UINT32_MAX) 58 | #define RANDOM_X64(type, func, rnd) 59 | #include 60 | #include "extra-xmacros.h" 61 | #undef RANDOM_X16 62 | #undef RANDOM_X32 63 | #undef RANDOM_X64 64 | bench_done(); 65 | putchar('\n'); 66 | } 67 | 68 | static void 69 | bench_rng_64(void) 70 | { 71 | puts("64-bit PRNGs"); 72 | #define RANDOM_X16(type, func, rnd) 73 | #define RANDOM_X32(type, func, rnd) 74 | #define RANDOM_X64(type, func, rnd) \ 75 | BENCH_RNG(#func, type, rnd(&rng), func(&rng), double, UINT64_MAX) 76 | #include 77 | #include "extra-xmacros.h" 78 | #undef RANDOM_X16 79 | #undef RANDOM_X32 80 | #undef RANDOM_X64 81 | bench_done(); 82 | putchar('\n'); 83 | } 84 | 85 | 86 | #define BENCH_NORM_IMPL(name, type, init, next, ftype) \ 87 | do { \ 88 | type rng; \ 89 | init(&rng); \ 90 | BENCH(name, 8, SAMPLES) { \ 91 | ftype x, y; \ 92 | size_t i, c; \ 93 | for (i = c = 0; i < COUNT; ++i) { \ 94 | x = next; \ 95 | y = next; \ 96 | if (x*x + y*y <= 1) \ 97 | ++c; \ 98 | } \ 99 | BENCH_VOLATILE(c); \ 100 | } \ 101 | } while (0); 102 | 103 | #define NORM_NEXT prng64_romu_duo_jr 104 | #define BENCH_NORM(name, next) BENCH_NORM_IMPL( \ 105 | name, PRNG64RomuDuo, prng64_romu_duo_randomize, next, double) 106 | 107 | #define NORMF_NEXT prng32_romu_trio 108 | #define BENCH_NORMF(name, next) BENCH_NORM_IMPL( \ 109 | name, PRNG32RomuTrio, prng32_romu_trio_randomize, next, float) 110 | 111 | 112 | 113 | static void 114 | bench_normal(void) 115 | { 116 | DistNormalZig zig; 117 | dist_normal_zig_init(&zig); 118 | 119 | puts("normal distribution using prng64_romu_duo_jr"); 120 | BENCH_NORM("dist_normalf_fast", dist_normalf_fast(NORM_NEXT(&rng))); 121 | BENCH_NORM("dist_normal", dist_normal(NORM_NEXT, &rng)); 122 | BENCH_NORM("dist_normal_zig", dist_normal_zig(&zig, NORM_NEXT, &rng)); 123 | 124 | bench_done(); 125 | putchar('\n'); 126 | } 127 | 128 | static void 129 | bench_normalf(void) 130 | { 131 | DistNormalfZig zig; 132 | dist_normalf_zig_init(&zig); 133 | 134 | puts("normal distribution using prng32_romu_trio"); 135 | BENCH_NORMF("dist_normalf", dist_normalf(NORMF_NEXT, &rng)); 136 | BENCH_NORMF("dist_normalf_zig", dist_normalf_zig(&zig, NORMF_NEXT, &rng)); 137 | 138 | bench_done(); 139 | putchar('\n'); 140 | } 141 | 142 | int 143 | main(void) 144 | { 145 | size_t i; 146 | puts("Note: Execution times between categories aren't comparable!\n"); 147 | 148 | bench_rng_16(); 149 | bench_rng_32(); 150 | bench_rng_64(); 151 | bench_normal(); 152 | bench_normalf(); 153 | 154 | bench_free(); 155 | return 0; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /test/stretchy-buffer/xtest.h: -------------------------------------------------------------------------------- 1 | void 2 | FUNC(void) 3 | { 4 | size_t i; 5 | T x; 6 | Sb(T) a = { 0 }, b = { 0 }; 7 | 8 | TEST_BEGIN((NAME)); 9 | 10 | for (i = 0; i < 32; ++i) 11 | sb_push(&a, RAND(x)); 12 | 13 | TEST_ASSERT(sb_len(a) == 32); 14 | 15 | for (i = 0; i < sb_len(a); ++i) 16 | sb_push(&b, a.at[i]); 17 | 18 | TEST_ASSERT(sb_len(b) == 32); 19 | 20 | for (i = 0; i < sb_len(a); ++i) 21 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 22 | 23 | RAND(x); 24 | sb_push(&a, x); 25 | TEST_ASSERT(EQ(a.at[sb_len(a) - 1], x)); 26 | TEST_ASSERT(sb_len(a) == 33); 27 | sb_pop(&a); 28 | TEST_ASSERT(sb_len(a) == 32); 29 | 30 | sb_addn(&a, 10); 31 | TEST_ASSERT(sb_len(a) == 42); 32 | 33 | sb_setlen(&b, 0); 34 | sb_reserve(&b, 10); 35 | TEST_ASSERT(sb_len(b) == 0); 36 | TEST_ASSERT(sb_cap(b) >= 10); 37 | 38 | /* the value argument should only be evaluated once */ 39 | for (i = 32; i < sb_len(a); ++i) 40 | sb_push(&b, (a.at[i] = RAND(x))); 41 | 42 | TEST_ASSERT(sb_len(b) == 10); 43 | 44 | for (i = 0; i < sb_len(b); ++i) 45 | TEST_ASSERT(EQ(b.at[i], a.at[i+32])); 46 | 47 | sb_rmn(&a, 0, 32); 48 | TEST_ASSERT(sb_len(a) == 10); 49 | 50 | for (i = 0; i < sb_len(a); ++i) 51 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 52 | 53 | sb_setcap(&a, 420); 54 | TEST_ASSERT(sb_cap(a) >= 420); 55 | sb_shrink(&a); 56 | 57 | sb_free(&b); 58 | sb_initlen(&b, 32); 59 | TEST_ASSERT(sb_len(b) == 32); 60 | TEST_ASSERT(sb_cap(b) >= 32); 61 | for (i = 0; i < sb_len(b); ++i) 62 | b.at[i] = RAND(x); 63 | 64 | sb_insn(&b, 10, 10); 65 | TEST_ASSERT(sb_len(b) == 42); 66 | for (i = 0; i < 10; ++i) 67 | b.at[10 + i] = a.at[i]; 68 | 69 | for (i = 0; i < 10; ++i) { 70 | x = b.at[19]; 71 | sb_rm(&b, 19); 72 | TEST_ASSERT(sb_len(b) == 41); 73 | sb_ins(&b, 0, x); 74 | TEST_ASSERT(sb_len(b) == 42); 75 | } 76 | 77 | TEST_ASSERT(sb_len(b) == 42); 78 | for (i = 0; i < 10; ++i) 79 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 80 | 81 | 82 | sb_free(&a); 83 | sb_initcap(&a, 42); 84 | TEST_ASSERT(sb_len(a) == 0); 85 | TEST_ASSERT(sb_cap(a) >= 42); 86 | 87 | for (i = 0; i < 42; ++i) 88 | sb_push(&a, b.at[i]); 89 | 90 | TEST_ASSERT(sb_len(a) == 42); 91 | 92 | sb_popn(&a, 9); 93 | TEST_ASSERT(sb_len(a) == 33); 94 | sb_pop(&a); 95 | TEST_ASSERT(sb_len(a) == 32); 96 | 97 | for (i = 0; i < 32; ++i) 98 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 99 | 100 | sb_free(&a); 101 | 102 | sb_addn(&a, 10); 103 | 104 | for (i = 0; i < 10; ++i) 105 | a.at[i] = RAND(x); 106 | sb_free(&b); 107 | sb_cpy(&b, a); 108 | 109 | TEST_ASSERT(sb_len(a) == 10); 110 | for (i = 0; i < 10; ++i) 111 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 112 | 113 | sb_rm(&a, 9); 114 | sb_rm(&a, 0); 115 | TEST_ASSERT(sb_len(a) == 8); 116 | for (i = 0; i < 8; ++i) 117 | TEST_ASSERT(EQ(a.at[i], b.at[i + 1])); 118 | 119 | sb_popn(&a, 8); 120 | TEST_ASSERT(sb_len(a) == 0); 121 | 122 | sb_ins(&a, 0, b.at[2]); 123 | sb_ins(&a, 0, b.at[0]); 124 | sb_ins(&a, 1, b.at[1]); 125 | sb_ins(&a, 3, b.at[3]); 126 | TEST_ASSERT(sb_len(a) == 4); 127 | for (i = 0; i < 4; ++i) 128 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 129 | 130 | sb_rmn(&a, 2, 2); 131 | TEST_ASSERT(sb_len(a) == 2); 132 | for (i = 0; i < 2; ++i) 133 | TEST_ASSERT(EQ(a.at[i], b.at[i])); 134 | 135 | sb_rm(&a, 0); 136 | sb_rm(&a, 0); 137 | TEST_ASSERT(sb_len(a) == 0); 138 | 139 | sb_rmn_unstable(&b, 5, 5); 140 | TEST_ASSERT(sb_len(b) == 5); 141 | sb_free(&a); 142 | 143 | sb_cpy(&a, b); 144 | sb_rm_unstable(&b, 3); 145 | TEST_ASSERT(sb_len(a) == 5); 146 | TEST_ASSERT(sb_len(b) == 4); 147 | TEST_ASSERT(EQ(a.at[0], b.at[0])); 148 | TEST_ASSERT(EQ(a.at[1], b.at[1])); 149 | TEST_ASSERT(EQ(a.at[2], b.at[2])); 150 | TEST_ASSERT(EQ(a.at[4], b.at[3])); 151 | 152 | { 153 | T arr[3]; 154 | arr[0] = RAND(x); 155 | arr[1] = RAND(x); 156 | arr[2] = RAND(x); 157 | 158 | sb_cpyarr(&a, arr); 159 | TEST_ASSERT(sb_len(a) == 3); 160 | TEST_ASSERT(EQ(a.at[0], arr[0])); 161 | TEST_ASSERT(EQ(a.at[1], arr[1])); 162 | TEST_ASSERT(EQ(a.at[2], arr[2])); 163 | 164 | sb_cpymem(&b, arr, 2); 165 | TEST_ASSERT(sb_len(b) == 2); 166 | TEST_ASSERT(EQ(b.at[0], arr[0])); 167 | TEST_ASSERT(EQ(b.at[1], arr[1])); 168 | } 169 | 170 | 171 | sb_free(&a); 172 | sb_free(&b); 173 | TEST_END(); 174 | } 175 | #undef T 176 | #undef NAME 177 | #undef FUNC 178 | 179 | -------------------------------------------------------------------------------- /cauldron/arena-allocator.h: -------------------------------------------------------------------------------- 1 | /* arena-allocator.h 2 | * Olaf Bernstein 3 | * Distributed under the MIT license, see license at the end of the file. 4 | * New versions available at https://github.com/camel-cdr/cauldron 5 | */ 6 | 7 | #ifndef ARENA_ALLOCATOR_H_INCLUDED 8 | 9 | #include 10 | 11 | #ifndef aa_BLOCK_SIZE 12 | #define aa_BLOCK_SIZE (16*1024) 13 | #endif 14 | 15 | typedef struct { 16 | /* blocks current 17 | * v v 18 | * {:} -> {:} -> {.} -> { } -> 0 */ 19 | struct aa_Block *blocks; 20 | struct aa_Block *current; 21 | } aa_Arena; 22 | 23 | extern void *aa_alloc(aa_Arena *arena, size_t size); 24 | extern void aa_dealloc(aa_Arena *arena); 25 | extern void aa_free(aa_Arena *arena); 26 | 27 | 28 | #define ARENA_ALLOCATOR_H_INCLUDED 29 | #endif 30 | 31 | /******************************************************************************/ 32 | 33 | #ifdef ARENA_ALLOCATOR_IMPLEMENT 34 | 35 | #include 36 | #include 37 | 38 | struct aa_Block { 39 | struct aa_Block *next; 40 | unsigned char *first; 41 | unsigned char *ptr; 42 | unsigned char *end; 43 | }; 44 | 45 | #if __STDC_VERSION__ >= 201112L 46 | # define aa_MAX_ALIGN _Alignof(max_align_t) 47 | #else 48 | union aa_MaxAlign { 49 | long double ld; 50 | long l; 51 | double d; 52 | char *p; 53 | int (*f)(void); 54 | # if __STDC_VERSION__ >= 199901L 55 | long long ll; 56 | # endif 57 | }; 58 | # define aa_MAX_ALIGN sizeof(union aa_MaxAlign) 59 | #endif 60 | 61 | void * 62 | aa_alloc(aa_Arena *arena, size_t size) 63 | { 64 | #define aa_ALIGN_UP(x, n) (((x) + (n) - 1) & ~((n) - 1)) 65 | 66 | struct aa_Block *it, *prev; 67 | size_t old = size; 68 | 69 | size = aa_ALIGN_UP(size, aa_MAX_ALIGN); 70 | it = prev = arena->current; 71 | 72 | /* find the first block with enough space */ 73 | assert(it ? it->end >= it->ptr : 1); 74 | while (it && size > (size_t)(it->end - it->ptr)) 75 | prev = it, it = it->next; 76 | 77 | if (it) { 78 | /* size fits in a block */ 79 | arena->current = it; 80 | it->ptr += size; 81 | } else { 82 | /* needs to be allocated */ 83 | size_t n = sizeof *it + size + aa_BLOCK_SIZE; 84 | size_t an = aa_ALIGN_UP(n, aa_MAX_ALIGN); 85 | it = malloc(an); 86 | if (arena->current) 87 | arena->current = prev->next = it; 88 | else 89 | arena->current = arena->blocks = it; 90 | it->next = 0; 91 | it->first = (unsigned char *)it + sizeof *it + (an - n); 92 | it->ptr = it->first + size; 93 | it->end = (unsigned char*)it + an; 94 | } 95 | 96 | return it->ptr - old; 97 | 98 | #undef aa_ALIGN_UP 99 | } 100 | 101 | void 102 | aa_dealloc(aa_Arena *arena) 103 | { 104 | struct aa_Block *it = arena->blocks; 105 | 106 | /* reset block->ptr to the beginning of the block */ 107 | while (it) { 108 | it->ptr = it->first; 109 | it = it->next; 110 | } 111 | 112 | arena->current = arena->blocks; 113 | } 114 | 115 | void 116 | aa_free(aa_Arena *arena) 117 | { 118 | struct aa_Block *it = arena->blocks; 119 | 120 | /* free all blocks */ 121 | while (it) { 122 | struct aa_Block *b = it; 123 | it = it->next; 124 | free(b); 125 | } 126 | 127 | arena->current = arena->blocks = 0; 128 | } 129 | 130 | #undef ARENA_ALLOCATOR_IMPLEMENT 131 | #endif 132 | 133 | /* 134 | * Copyright (c) 2022 Olaf Berstein 135 | * Permission is hereby granted, free of charge, to any person obtaining a copy 136 | * of this software and associated documentation files (the "Software"), to deal 137 | * in the Software without restriction, including without limitation the rights 138 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 139 | * copies of the Software, and to permit persons to whom the Software is 140 | * furnished to do so, subject to the following conditions: 141 | * The above copyright notice and this permission notice shall be included in 142 | * all copies or substantial portions of the Software. 143 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 144 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 145 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 146 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 147 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 148 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 149 | * SOFTWARE. 150 | */ 151 | 152 | -------------------------------------------------------------------------------- /tools/random/dist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define RANDOM_H_IMPLEMENTATION 9 | #include 10 | #include 11 | 12 | /* 13 | * Example: 14 | * ./rng | ./dist -n 100000 n32 | ./freqency.gp 15 | */ 16 | 17 | static char *argv0; 18 | 19 | static uint32_t 20 | rand32(void *arg) 21 | { 22 | (void)arg; 23 | uint32_t x; 24 | fread(&x, sizeof x, 1, stdin); 25 | return x; 26 | } 27 | 28 | static uint64_t 29 | rand64(void *arg) 30 | { 31 | (void)arg; 32 | uint64_t x; 33 | fread(&x, sizeof x, 1, stdin); 34 | return x; 35 | } 36 | 37 | static void 38 | usage(void) 39 | { 40 | printf("Usage: %s [OPTION...] DISRIBUTION\n", argv0); 41 | puts("Distribute random data from standard input according to DISRIBUTION.\n"); 42 | 43 | puts("Options:"); 44 | puts(" -p, --float-precision=NUM print float with NUM decimal places"); 45 | puts(" -n, -c, --count=NUM quit after NUM outputs"); 46 | puts(" -h, --help display this help and exit\n"); 47 | 48 | puts("Distributions:"); 49 | puts(" u32 [MAX] uniform unsigned 32-bit integers"); 50 | puts(" u64 [MAX] uniform unsigned 64-bit integers"); 51 | puts(" f32 uniform 32-bit floating point"); 52 | puts(" f64 uniform 64-bit floating point"); 53 | puts(" f32d MIN MAX uniform 32-bit floating point dense"); 54 | puts(" f64d MIN MAX uniform 64-bit floating point dense"); 55 | puts(" n32 normal distributed 32-bit floating point"); 56 | puts(" n64 normal distributed 64-bit floating point"); 57 | puts(" n32z normal distributed 32-bit floating point"); 58 | puts(" using the ziggurat method"); 59 | puts(" n64z normal distributed 64-bit floating point"); 60 | puts(" using the ziggurat method"); 61 | puts(" n32f normal distributed 64-bit floating point"); 62 | puts(" approximated using"); 63 | } 64 | 65 | int 66 | main(int argc, char **argv) 67 | { 68 | int precision = 6; 69 | size_t count = SIZE_MAX; 70 | 71 | argv0 = argv[0]; 72 | 73 | (void)freopen(0, "rb", stdin); 74 | 75 | 76 | ARG_BEGIN { 77 | if (ARG_LONG("help")) case 'h': case '?': { 78 | usage(); 79 | return EXIT_SUCCESS; 80 | } else if (ARG_LONG("count")) case 'n': case 'c': { 81 | sscanf(ARG_VAL(), "%zu", &count); 82 | } else if (ARG_LONG("float-precision")) case 'p': { 83 | precision = atoi(ARG_VAL()); 84 | } else default: { 85 | fprintf(stderr, 86 | "%s: invalid option '%s'\n" 87 | "Try '%s --help' for more information.\n", 88 | argv0, *argv, argv0); 89 | return EXIT_FAILURE; 90 | } 91 | } ARG_END; 92 | 93 | if (argc < 1) { 94 | usage(); 95 | return EXIT_FAILURE; 96 | } 97 | 98 | for (; argv[0]; --argc, ++argv) { 99 | /* */ if (strcmp(*argv, "u32") == 0) { 100 | uint32_t max = UINT32_MAX; 101 | if ((argv)[1]) 102 | sscanf((++argv)[0], "%"PRIu32, &max); 103 | while (count--) 104 | printf("%"PRIu32"\n", dist_uniform_u32(max, rand32, 0)); 105 | } else if (strcmp(*argv, "u64") == 0) { 106 | uint64_t max = UINT64_MAX; 107 | if ((argv)[1]) 108 | sscanf((++argv)[0], "%"PRIu64, &max); 109 | while (count--) 110 | printf("%"PRIu64"\n", dist_uniform_u64(max, rand64, 0)); 111 | } else if (strcmp(*argv, "f32") == 0) { 112 | while (count--) 113 | printf("%.*g\n", precision, dist_uniformf(rand32(0))); 114 | } else if (strcmp(*argv, "f64") == 0) { 115 | while (count--) 116 | printf("%.*g\n", precision, dist_uniform(rand64(0))); 117 | } else if (strcmp(*argv, "f32d") == 0) { 118 | float a = atof(argv[1]); 119 | float b = atof(argv[2]); 120 | argc -= 2; 121 | argv += 2; 122 | while (count--) 123 | printf("%.*g\n", precision, 124 | dist_uniformf_dense(a, b, rand32, 0)); 125 | } else if (strcmp(*argv, "f64d") == 0) { 126 | double a = atof(argv[1]); 127 | double b = atof(argv[2]); 128 | argc -= 2; 129 | argv += 2; 130 | while (count--) 131 | printf("%.*g\n", precision, 132 | dist_uniform_dense(a, b, rand64, 0)); 133 | } else if (strcmp(*argv, "n32") == 0) { 134 | while (count--) 135 | printf("%.*g\n", precision, dist_normalf(rand32, 0)); 136 | } else if (strcmp(*argv, "n64") == 0) { 137 | while (count--) 138 | printf("%.*g\n", precision, dist_normal(rand64, 0)); 139 | } else if (strcmp(*argv, "n32z") == 0) { 140 | DistNormalfZig zig; 141 | dist_normalf_zig_init(&zig); 142 | while (count--) 143 | printf("%.*g\n", precision, dist_normalf_zig(&zig, rand32, 0)); 144 | } else if (strcmp(*argv, "n64z") == 0) { 145 | DistNormalZig zig; 146 | dist_normal_zig_init(&zig); 147 | while (count--) 148 | printf("%.*g\n", precision, dist_normal_zig(&zig, rand64, 0)); 149 | } else if (strcmp(*argv, "n32f") == 0) { 150 | while (count--) 151 | printf("%.*g\n", precision, dist_normalf_fast(rand64(0))); 152 | } else { 153 | fprintf(stderr, "%s: invalid distribution -- '%s'\n", argv0, *argv); 154 | fprintf(stderr, "Try '%s --help' for more information.\n", argv0); 155 | return EXIT_FAILURE; 156 | } 157 | } 158 | 159 | return EXIT_FAILURE; 160 | } 161 | -------------------------------------------------------------------------------- /cauldron/arg.h: -------------------------------------------------------------------------------- 1 | /* arg.h -- A POSIX compliant argument parser based on plan9's arg(3) 2 | * Olaf Bernstein 3 | * Distributed under the MIT license, see license at the end of the file. 4 | * New versions available at https://github.com/camel-cdr/cauldron 5 | */ 6 | 7 | #ifndef ARG_H_INCLUDED 8 | 9 | static int 10 | ARG_LONG_func(char **argv0, char const *name) 11 | { 12 | char *argIt = *argv0; 13 | while (*argIt == *name && *argIt) 14 | argIt++, name++; 15 | if (*argIt == *name || (*argIt == '=' && !*name)) { 16 | *argv0 = argIt; 17 | return 1; 18 | } 19 | return 0; 20 | } 21 | 22 | #define ARG_BEGIN do { \ 23 | for (argv[0] && (--argc, ++argv); \ 24 | argv[0] && argv[0][0] == '-'; \ 25 | argv[0] && (--argc, ++argv)) { \ 26 | int isFlag = 1; \ 27 | char *arg = argv[0]; \ 28 | if (arg[1] == '-' && arg[2] == 0 && (--argc, ++argv, 1)) \ 29 | break; \ 30 | ARG_BEGIN_REP: \ 31 | switch ((++arg)[0]) { \ 32 | case '-': \ 33 | isFlag = 0; \ 34 | if (arg[-1] == '-') \ 35 | ++arg; 36 | 37 | #define ARG_LONG(name) ARG_LONG_func(&(arg), (name)) 38 | 39 | #define ARG_VAL() \ 40 | (isFlag ? (arg[1] ? ++arg : *(--argc, ++argv)) : \ 41 | (arg[0] == '=' ? ++arg : *(--argc, ++argv))) 42 | 43 | #define ARG_FLAG() if (isFlag && arg[1]) goto ARG_BEGIN_REP 44 | 45 | #define ARG_END } } } while(0) 46 | 47 | #define ARG_H_INCLUDED 48 | #endif 49 | 50 | 51 | /* 52 | * Example: 53 | */ 54 | 55 | #if defined(ARG_EXAMPLE) || defined(ARG_FUZZ) 56 | 57 | #include 58 | #include 59 | 60 | #ifdef ARG_FUZZ 61 | #define main argMain 62 | #undef stderr 63 | #define stderr stdout 64 | #endif 65 | 66 | 67 | int 68 | main(int argc, char **argv) 69 | { 70 | char *argv0 = argv[0]; 71 | int a = 0, b = 0, c = 0, reverse = 0; 72 | char const *input = "default", *output = "default"; 73 | int readstdin = 0; 74 | 75 | ARG_BEGIN { 76 | if (0) { 77 | case 'a': a = 1; ARG_FLAG(); break; 78 | case 'b': b = 1; ARG_FLAG(); break; 79 | case 'c': c = 1; ARG_FLAG(); break; 80 | case '\0': readstdin = 1; break; 81 | } else if (ARG_LONG("reverse")) case 'r': { 82 | reverse = 1; 83 | ARG_FLAG(); 84 | } else if (ARG_LONG("input")) case 'i': { 85 | input = ARG_VAL(); 86 | } else if (ARG_LONG("output")) case 'o': { 87 | output = ARG_VAL(); 88 | } else if (ARG_LONG("help")) case 'h': case '?': { 89 | printf("Usage: %s [OPTION...] [STRING...]\n", argv0); 90 | puts("Example usage of arg.h\n"); 91 | puts("Options:"); 92 | puts(" -a, set a to true"); 93 | puts(" -b, set b to true"); 94 | puts(" -c, set c to true"); 95 | puts(" -r, --reverse set reverse to true"); 96 | puts(" -i, --input=STR set input string to STR"); 97 | puts(" -o, --output=STR set output string to STR"); 98 | puts(" -h, --help display this help and exit"); 99 | return EXIT_SUCCESS; 100 | } else { default: 101 | fprintf(stderr, 102 | "%s: invalid option '%s'\n" 103 | "Try '%s --help' for more information.\n", 104 | argv0, *argv, argv0); 105 | return EXIT_FAILURE; 106 | } 107 | } ARG_END; 108 | 109 | printf("a = %s\n", a ? "true" : "false"); 110 | printf("b = %s\n", b ? "true" : "false"); 111 | printf("c = %s\n", c ? "true" : "false"); 112 | printf("reverse = %s\n", reverse ? "true" : "false"); 113 | printf("readstdin = %s\n", readstdin ? "true" : "false"); 114 | printf("input = %s\n", input); 115 | printf("output = %s\n", output); 116 | 117 | printf("\nargc: %d", argc); 118 | puts("\nargv:"); 119 | while (*argv) 120 | printf(" %s\n", *argv++); 121 | 122 | return 0; 123 | } 124 | 125 | #endif /* ARG_EXAMPLE */ 126 | 127 | /* 128 | * Fuzzing: 129 | */ 130 | 131 | #ifdef ARG_FUZZ 132 | 133 | #include 134 | #include 135 | #define MAX_ARGC 50000 136 | 137 | int 138 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 139 | { 140 | if (size < 2) 141 | return -1; 142 | 143 | char *buf = malloc(size+2); 144 | memcpy(buf, data, size); 145 | buf[size] = buf[size+1] = 0; 146 | 147 | static char *argv[MAX_ARGC+1]; 148 | size_t argc = 0; 149 | for (char *ptr = buf; *ptr && argc < MAX_ARGC;) { 150 | argv[argc++] = ptr; 151 | while (*ptr++); 152 | } 153 | argv[argc] = 0; 154 | 155 | main(argc, argv); 156 | free(buf); 157 | 158 | return 0; 159 | } 160 | 161 | #endif 162 | 163 | 164 | /* 165 | * Copyright (c) 2021 Olaf Berstein 166 | * Permission is hereby granted, free of charge, to any person obtaining a copy 167 | * of this software and associated documentation files (the "Software"), to deal 168 | * in the Software without restriction, including without limitation the rights 169 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 170 | * copies of the Software, and to permit persons to whom the Software is 171 | * furnished to do so, subject to the following conditions: 172 | * The above copyright notice and this permission notice shall be included in 173 | * all copies or substantial portions of the Software. 174 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 176 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 177 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 178 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 179 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 180 | * SOFTWARE. 181 | */ 182 | 183 | -------------------------------------------------------------------------------- /cauldron/stretchy-buffer.h: -------------------------------------------------------------------------------- 1 | /* stretchy-buffer.h -- generic dynamic array 2 | * Olaf Bernstein 3 | * Distributed under the MIT license, see license at the end of the file. 4 | * New versions available at https://github.com/camel-cdr/cauldron 5 | * 6 | * Inspired by Sean Barrett's stretchy-buffers and klib's kvec. 7 | * 8 | * Note that any arguments passed to a sb_* function macros is potentially 9 | * evaluated multiple times except for arguments that have the name v in the 10 | * code bellow. 11 | */ 12 | 13 | #ifndef STRETCHY_BUFFER_H_INCLUDED 14 | 15 | 16 | /* by default: exit on allocation failure */ 17 | 18 | #if !(defined sb_malloc) || !(defined sb_realloc) 19 | #include 20 | #include 21 | 22 | static inline void * 23 | sb__realloc(void *ptr, size_t num_bytes) 24 | { 25 | if (!(ptr = realloc(ptr, num_bytes))) 26 | perror("realloc failed"), exit(EXIT_FAILURE); 27 | return ptr; 28 | } 29 | #endif 30 | 31 | #ifndef sb_malloc 32 | #define sb_malloc(s) sb__realloc((void*)0, s) 33 | #endif 34 | #ifndef sb_realloc 35 | #define sb_realloc(p,s) sb__realloc(p, s) 36 | #endif 37 | 38 | 39 | 40 | /* can be zero initialized */ 41 | #define Sb(T) struct { T *at; size_t _len, _cap; } 42 | 43 | #define sb_len(a) (+(a)._len) 44 | #define sb_cap(a) (+(a)._cap) 45 | 46 | #define sb_begin(a) ((a).at) 47 | #define sb_last(a) ((a).at + (a)._len - 1) 48 | #define sb_end(a) ((a).at + (a)._len) 49 | 50 | #define sb_initcap(a,n) ((a)->_len = 0, (a)->_cap = (n), \ 51 | (a)->at = sb_malloc((a)->_cap * sizeof *(a)->at)) 52 | #define sb_initlen(a,n) ((a)->_len = (a)->_cap = (n), \ 53 | (a)->at = sb_malloc((a)->_cap * sizeof *(a)->at)) 54 | 55 | #define sb_cpy(dest, src) \ 56 | (sb_setlen((dest), (src)._len), \ 57 | memcpy((dest)->at, (src).at, (dest)->_len * sizeof *(dest)->at)) 58 | 59 | #define sb_cpymem(dest, src, n) \ 60 | (assert(sizeof *(dest)->at == sizeof *(src)), \ 61 | sb_setlen((dest), (n)), \ 62 | memcpy((dest)->at, (src), (dest)->_len * sizeof *(dest)->at)) 63 | 64 | #define sb_cpyarr(dest, src) \ 65 | (sb_setlen((dest), sizeof (src) / sizeof *(src)), \ 66 | memcpy((dest)->at, (src), sizeof (src))) 67 | 68 | 69 | #define sb_setlen(a,n) ((a)->_len = (n), sb_setcap((a), (a)->_len)) 70 | #define sb_setcap(a,n) ((a)->_cap < (n) ? \ 71 | ((a)->_cap = ((a)->_cap * 3 >> 1) | (n), \ 72 | (a)->at = sb_realloc((a)->at, (a)->_cap * sizeof *(a)->at)) : 0) 73 | #define sb_reserve(a,n) sb_setcap((a), (a)->_cap + (n)) 74 | 75 | #define sb_push(a,v) (sb_setlen((a), (a)->_len + 1), (a)->at[(a)->_len - 1] = (v)) 76 | #define sb_addn(a,n) sb_setlen((a), (a)->_len + (n)) 77 | 78 | #define sb_free(a) (free((a)->at), (a)->at = 0, (a)->_len = (a)->_cap = 0) 79 | #define sb_shrink(a) ((((a)->_cap = (a)->_len) == 0) ? sb_free(a), 0 : \ 80 | ((a)->at = realloc((a)->at, (a)->_cap * sizeof *(a)->at), 0)) 81 | 82 | /* n <= sb_len && n > 0*/ 83 | #define sb_popn(a,n) (assert((n) <= (a)->_len && (n) > 0), (a)->_len -= (n)) 84 | #define sb_pop(a) (sb_popn((a), 1)) 85 | 86 | /* n + i <= sb_len && i >= 0 && n > 0 */ 87 | #define sb_rmn(a,i,n) (assert((n) + (i) <= (a)->_len && (i) >= 0 && (n) > 0), \ 88 | memmove((a)->at + (i), (a)->at + (i) + (n), \ 89 | (((a)->_len -= (n)) - (i)) * sizeof *(a)->at)) 90 | #define sb_rm(a,i) sb_rmn((a), (i), 1) 91 | 92 | /* faster rm, that doesn't preserve order */ 93 | /* n + i <= sb_len && i >= 0 && n > 0*/ 94 | #define sb_rmn_unstable(a,i,n) \ 95 | (assert((n) + (i) <= (a)->_len && (i) >= 0 && (n) > 0), \ 96 | memmove((a)->at + (i), \ 97 | (a)->at + ((a)->_len -= (n)) - 1, \ 98 | (n) * sizeof *(a)->at)) 99 | #define sb_rm_unstable(a,i) ((a)->at[i] = (a)->at[(a)->_len -= 1]) 100 | 101 | /* 0 <= i <= sb_len */ 102 | #define sb_insn(a,i,n) (assert(0 <= (i) && (i) <= (a)->_len), \ 103 | (sb_addn((a), (n)), \ 104 | memmove((a)->at + (i) + (n), (a)->at + (i), \ 105 | ((a)->_len - (n) - (i)) * sizeof *(a)->at))) 106 | #define sb_ins(a,i,v) (sb_insn((a), (i), 1), (a)->at[i] = (v)) 107 | 108 | #define STRETCHY_BUFFER_H_INCLUDED 109 | #endif 110 | 111 | /* 112 | * Example: 113 | */ 114 | 115 | #ifdef STRETCHY_BUFFER_EXAMPLE 116 | 117 | #include 118 | #include 119 | 120 | int 121 | main(void) 122 | { 123 | /* You could also typedef Sb(int) to be able to pass it to functions */ 124 | int i; 125 | Sb(int) fib = { 0 }; 126 | sb_push(&fib, 1); 127 | sb_push(&fib, 1); 128 | 129 | for (i = 2; i < 32; ++i) 130 | sb_push(&fib, fib.at[i-1] + fib.at[i-2]); 131 | 132 | return 0; 133 | } 134 | 135 | #endif /* STRETCHY_BUFFER_EXAMPLE */ 136 | 137 | 138 | /* 139 | * Copyright (c) 2022 Olaf Berstein 140 | * Permission is hereby granted, free of charge, to any person obtaining a copy 141 | * of this software and associated documentation files (the "Software"), to deal 142 | * in the Software without restriction, including without limitation the rights 143 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 144 | * copies of the Software, and to permit persons to whom the Software is 145 | * furnished to do so, subject to the following conditions: 146 | * The above copyright notice and this permission notice shall be included in 147 | * all copies or substantial portions of the Software. 148 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 149 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 150 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 151 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 152 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 153 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 154 | * SOFTWARE. 155 | */ 156 | 157 | -------------------------------------------------------------------------------- /tools/random/extra.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Note: These PRNGs vary in quality, don't just blindly start using them! 5 | */ 6 | 7 | #ifndef EXTRA_H_INCLUDED 8 | 9 | /* Middle Square Weyl Sequence RNG: Bernard Widynski 10 | * https://arxiv.org/abs/1704.00358 */ 11 | 12 | typedef struct { uint32_t s[2]; } PRNG16Msws; 13 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG16Msws, prng16_msws) 14 | static inline uint16_t 15 | prng16_msws(void *rng) 16 | { 17 | PRNG16Msws *r = rng; 18 | r->s[0] = r->s[0]*r->s[0] + (r->s[1] += 0x97DEF15B); 19 | return r->s[0] = (r->s[0] >> 16) | (r->s[0] << 16); 20 | } 21 | 22 | typedef struct { uint64_t s[2]; } PRNG32Msws; 23 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG32Msws, prng32_msws) 24 | static inline uint32_t 25 | prng32_msws(void *rng) 26 | { 27 | PRNG32Msws *r = rng; 28 | r->s[0] = r->s[0]*r->s[0] + (r->s[1] += 0x6BC13D2FD5B92843); 29 | return r->s[0] = (r->s[0] >> 32) | (r->s[0] << 32); 30 | } 31 | 32 | #if __SIZEOF_INT128__ 33 | typedef struct { __uint128_t s[2]; } PRNG64Msws; 34 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Msws, prng64_msws) 35 | static inline uint64_t 36 | prng64_msws(void *rng) 37 | { 38 | PRNG64Msws *r = rng; 39 | r->s[0] = r->s[0]*r->s[0] + (r->s[1] += (__uint128_t)0x79A23B1C581C2693 << 64 | 0xEAB63C54A351C269); 40 | return r->s[0] = (r->s[0] >> 64) | (r->s[0] << 64); 41 | } 42 | #endif 43 | 44 | typedef struct { uint64_t s[4]; } PRNG64Msws64_2x32; 45 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Msws64_2x32, prng64_msws_2x32bit) 46 | static inline uint64_t 47 | prng64_msws_2x32bit(void *rng) 48 | { 49 | PRNG64Msws64_2x32 *r = rng; 50 | r->s[0] = r->s[0]*r->s[0] + (r->s[2] += 0x9126B7F4D352FCB7); 51 | r->s[1] = r->s[1]*r->s[1] + (r->s[3] += 0x4352BDCE94BCE365); 52 | r->s[0] = (r->s[0] >> 32) | (r->s[0] << 32); 53 | r->s[1] = (r->s[1] >> 32) | (r->s[1] << 32); 54 | return (r->s[0] << 32) | (r->s[1] & ((UINT64_C(1) << 32) - 1)); 55 | } 56 | 57 | 58 | /* SFC: Chris Doty-Humphrey 59 | * https://sourceforge.net/projects/pracrand/ */ 60 | 61 | typedef struct { uint16_t s[4]; } PRNG16Sfc; 62 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG16Sfc, prng16_sfc) 63 | static inline uint16_t 64 | prng16_sfc(void *rng) 65 | { 66 | PRNG16Sfc *r = rng; 67 | enum { BARREL_SHIFT = 6, RSHIFT = 5, LSHIFT = 3 }; 68 | uint16_t const tmp = r->s[0] + r->s[1] + r->s[3]++; 69 | r->s[0] = r->s[1] ^ (r->s[1] >> RSHIFT); 70 | r->s[1] = r->s[2] + (r->s[2] << LSHIFT); 71 | r->s[2] = ((r->s[2] << BARREL_SHIFT) | (r->s[2] >> (16 - BARREL_SHIFT))) + tmp; 72 | return tmp; 73 | } 74 | 75 | typedef struct { uint32_t s[4]; } PRNG32Sfc; 76 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG32Sfc, prng32_sfc) 77 | static inline uint32_t 78 | prng32_sfc(void *rng) 79 | { 80 | PRNG32Sfc *r = rng; 81 | enum { BARREL_SHIFT = 21, RSHIFT = 9, LSHIFT = 3 }; 82 | uint32_t const tmp = r->s[0] + r->s[1] + r->s[3]++; 83 | r->s[0] = r->s[1] ^ (r->s[1] >> RSHIFT); 84 | r->s[1] = r->s[2] + (r->s[2] << LSHIFT); 85 | r->s[2] = ((r->s[2] << BARREL_SHIFT) | (r->s[2] >> (32 - BARREL_SHIFT))) + tmp; 86 | return tmp; 87 | } 88 | 89 | typedef struct { uint64_t s[4]; } PRNG64Sfc; 90 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Sfc, prng64_sfc) 91 | static inline uint64_t 92 | prng64_sfc(void *rng) 93 | { 94 | PRNG64Sfc *r = rng; 95 | enum { BARREL_SHIFT = 24, RSHIFT = 11, LSHIFT = 3 }; 96 | uint64_t const tmp = r->s[0] + r->s[1] + r->s[3]++; 97 | r->s[0] = r->s[1] ^ (r->s[1] >> RSHIFT); 98 | r->s[1] = r->s[2] + (r->s[2] << LSHIFT); 99 | r->s[2] = ((r->s[2] << BARREL_SHIFT) | (r->s[2] >> (64 - BARREL_SHIFT))) + tmp; 100 | return tmp; 101 | } 102 | 103 | 104 | /* tylo64: Tyge Løvset's modified SFC64 105 | * https://github.com/numpy/numpy/issues/16313#issuecomment-641897028 */ 106 | 107 | typedef struct {uint64_t s[4];} PRNG64Tylo; 108 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Tylo, prng64_tylo) 109 | static inline uint64_t 110 | prng64_tylo(void *rng) 111 | { 112 | PRNG64Tylo *r = rng; 113 | enum { LROT = 24, RSHIFT = 11, LSHIFT = 3 }; 114 | uint64_t const s1 = r->s[1], out = r->s[0] ^ (r->s[2] += r->s[3]); 115 | r->s[0] = (s1 + (s1 << LSHIFT)) ^ (s1 >> RSHIFT); 116 | r->s[1] = ((s1 << LROT) | (s1 >> (64 - LROT))) + out; 117 | return out; 118 | } 119 | 120 | 121 | /* JSF: Robert Jenkins 122 | * https://burtleburtle.net/bob/rand/smallprng.html */ 123 | 124 | typedef struct { uint32_t s[4]; } PRNG32Jfs; 125 | static void 126 | prng32_jfs_randomize(void *rng) 127 | { 128 | PRNG32Jfs *r = rng; 129 | trng_write(r->s, sizeof r->s); 130 | r->s[0] = 0xF1EA5EED; 131 | } 132 | static inline uint32_t 133 | prng32_jfs(void *rng) 134 | { 135 | PRNG32Jfs *r = rng; 136 | uint32_t const e = r->s[0] - ((r->s[1] << 27) | (r->s[1] >> 5)); 137 | r->s[0] = r->s[1] ^ ((r->s[2] << 17) | (r->s[2] >> 15)); 138 | r->s[1] = r->s[2] + r->s[3]; 139 | r->s[2] = r->s[3] + e; 140 | r->s[3] = e + r->s[0]; 141 | return r->s[3]; 142 | } 143 | 144 | typedef struct { uint64_t s[4]; } PRNG64Jfs; 145 | static inline void 146 | prng64_jfs_randomize(void *rng) 147 | { 148 | PRNG64Jfs *r = rng; 149 | trng_write(r->s, sizeof r->s); 150 | r->s[0] = 0xF1EA5EED; 151 | } 152 | static inline uint64_t 153 | prng64_jfs(void *rng) 154 | { 155 | PRNG64Jfs *r = rng; 156 | uint64_t const e = r->s[0] - ((r->s[1] << 39) | (r->s[1] >> 25)); 157 | r->s[0] = r->s[1] ^ ((r->s[2] << 11) | (r->s[2] >> 53)); 158 | r->s[1] = r->s[2] + r->s[3]; 159 | r->s[2] = r->s[3] + e; 160 | r->s[3] = e + r->s[0]; 161 | return r->s[3]; 162 | } 163 | 164 | 165 | /* xorshift128+: Sebastiano Vigna 166 | * https://web.archive.org/web/20150114061109/http://xorshift.di.unimi.it/ */ 167 | 168 | typedef struct { uint64_t s[2]; } PRNG64Xorshift128p; 169 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Xorshift128p, prng64_xorshift128p) 170 | static inline uint64_t 171 | prng64_xorshift128p(void *rng) 172 | { 173 | PRNG64Xorshift128p *r = rng; 174 | uint64_t s1 = r->s[0]; 175 | uint64_t const s0 = r->s[1]; 176 | r->s[0] = s0; 177 | s1 ^= s1 << 23; 178 | return (r->s[1] = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26))) + s0; 179 | } 180 | 181 | typedef struct { uint64_t s[1]; } PRNG64Xorshift64; 182 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG64Xorshift64, prng64_xorshift64) 183 | static inline uint64_t 184 | prng64_xorshift64(void *rng) 185 | { 186 | PRNG64Xorshift64 *r = rng; 187 | r->s[0] ^= r->s[0] << 13; 188 | r->s[0] ^= r->s[0] >> 7; 189 | r->s[0] ^= r->s[0] << 17; 190 | return r->s[0]; 191 | } 192 | 193 | 194 | 195 | /* https://github.com/openjdk/jdk/blob/master/src/ 196 | * java.base/share/classes/java/util/Random.java */ 197 | 198 | typedef struct { uint32_t s[1]; } PRNG32JavaUtilRandom; 199 | CAULDRON_MAKE_PRNG_NOTALLZERO_RANDOMIZE(PRNG32JavaUtilRandom, prng32_java_util_random) 200 | static inline uint32_t 201 | prng32_java_util_random(void *rng) 202 | { 203 | PRNG32JavaUtilRandom *r = rng; 204 | r->s[1] = (r->s[1] * 0x5DEECE66Du + 0xBu) & ((UINT64_C(1) << 48) - 1); 205 | return r->s[1] >> (48 - 32); 206 | } 207 | 208 | 209 | 210 | #define EXTRA_H_INCLUDED 211 | #endif 212 | 213 | -------------------------------------------------------------------------------- /cauldron/bench.h: -------------------------------------------------------------------------------- 1 | /* bench.h -- A minimal benchmarking library 2 | * Olaf Bernstein 3 | * Distributed under the MIT license, see license at the end of the file. 4 | * New versions available at https://github.com/camel-cdr/cauldron 5 | */ 6 | 7 | #ifndef BENCH_H_INCLUDED 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if !defined(__pnacl__) && !defined(__EMSCRIPTEN__) && \ 18 | (defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER)) 19 | 20 | /* artificial use of all of memory */ 21 | # define BENCH_CLOBBER() asm volatile("":::"memory") 22 | /* artificial dependency of x on all of memory and all of memory on x */ 23 | # define BENCH_VOLATILE(x) asm volatile("" : "+g"(x) : "g"(x) : "memory") 24 | # define BENCH_VOLATILE_REG(x) asm volatile("" : "+r"(x) : "r"(x) : "memory") 25 | # define BENCH_VOLATILE_MEM(x) asm volatile("" : "+m"(x) : "m"(x) : "memory") 26 | 27 | #else 28 | 29 | # if defined(_MSC_VER) 30 | # pragma optimize("", off) 31 | static inline void bench__use_ptr(void const volatile *x) {} 32 | /* artificial use of all of memory */ 33 | # define BENCH_CLOBBER() _ReadWriteBarrier() 34 | # pragma optimize("", on) 35 | # else 36 | static void bench_use_ptr(char const volatile *x) {} 37 | /* artificial use of all of memory */ 38 | # define BENCH_CLOBBER() 39 | # endif 40 | 41 | /* artificial use of all of memory dependent on x */ 42 | # define BENCH_CLOBBER_WITH(x) (bench__use_ptr(&(x)), BENCH_CLOBBER()) 43 | # define BENCH_CLOBBER_WITH_REG(x) (bench__use_ptr(&(x)), BENCH_CLOBBER()) 44 | # define BENCH_CLOBBER_WITH_MEM(x) (bench__use_ptr(&(x)), BENCH_CLOBBER()) 45 | 46 | #endif 47 | 48 | 49 | typedef struct { 50 | size_t count; 51 | double min, mean, M2; 52 | char const *title; 53 | } BenchRecord; 54 | 55 | typedef struct { 56 | size_t count, cap; 57 | BenchRecord *records; 58 | /* temporaries */ 59 | size_t i; 60 | double secs; 61 | } Bench; 62 | 63 | static Bench benchInternal; 64 | 65 | #define BENCH(title, warmup, samples) \ 66 | for (bench_append(title), \ 67 | benchInternal.i = (warmup) + (samples); \ 68 | (benchInternal.secs = bench_gettime()), benchInternal.i--; \ 69 | benchInternal.i < (samples) ? \ 70 | bench_update(bench_gettime()-benchInternal.secs),0 : 0) 71 | 72 | static inline double 73 | bench_gettime(void) 74 | { 75 | #if defined(CLOCK_PROCESS_CPUTIME_ID) 76 | struct timespec t; 77 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t); 78 | return t.tv_nsec * 1.0/1000000000 + t.tv_sec; 79 | #elif defined(CLOCK_MONOTONIC_RAW) 80 | struct timespec t; 81 | clock_gettime(CLOCK_MONOTONIC_RAW, &t); 82 | return t.tv_nsec * 1.0/1000000000 + t.tv_sec; 83 | #else 84 | return clock() * 1.0 / CLOCKS_PER_SEC; 85 | #endif 86 | } 87 | 88 | static inline void 89 | bench_append(char const *title) 90 | { 91 | Bench *b = &benchInternal; 92 | BenchRecord *r; 93 | if (b->count >= b->cap) { 94 | b->cap = (b->cap << 1) + 1; 95 | b->records = (BenchRecord *) 96 | realloc(b->records, b->cap * sizeof *b->records); 97 | } 98 | r = &b->records[b->count++]; 99 | r->mean = r->M2 = r->count = 0; 100 | r->min = DBL_MAX; 101 | r->title = title; 102 | } 103 | 104 | static inline void 105 | bench_update(double time) 106 | { 107 | BenchRecord *r = &benchInternal.records[benchInternal.count-1]; 108 | double const delta = time - r->mean; 109 | r->mean += delta / ++r->count; 110 | r->M2 += delta * (time - r->mean); 111 | if (time < r->min) 112 | r->min = time; 113 | } 114 | 115 | static inline int 116 | bench_record_cmp(void const *lhs, void const *rhs) 117 | { 118 | BenchRecord const *l = (BenchRecord const *)lhs; 119 | BenchRecord const *r = (BenchRecord const *)rhs; 120 | return l->mean > r->mean ? 1 : -1; 121 | } 122 | 123 | static inline void 124 | bench_done(void) 125 | { 126 | size_t i, j, maxlen; 127 | double minmean = DBL_MAX; 128 | Bench *b = &benchInternal; 129 | qsort(b->records, b->count, sizeof *b->records, bench_record_cmp); 130 | 131 | for (maxlen = i = 0; i < b->count; ++i) { 132 | size_t l = strlen(b->records[i].title); 133 | if (l > maxlen) 134 | maxlen = l; 135 | if (b->records[i].mean < minmean) 136 | minmean = b->records[i].mean; 137 | } 138 | 139 | for (i = 0; i < b->count; ++i) { 140 | int l = printf("%s:", b->records[i].title) - 4; 141 | 142 | for (j = 0; j < maxlen-l; ++j) 143 | putchar(' '); 144 | 145 | printf("mean: %.9e, stddev: %.2e, min: %.9e \n", 146 | #ifdef BENCH_DONT_NORMALIZE 147 | b->records[i].mean, 148 | sqrt(b->records[i].M2 / b->records[i].count), 149 | #else 150 | b->records[i].mean / minmean, 151 | sqrt(b->records[i].M2 / b->records[i].count) / minmean, 152 | #endif 153 | b->records[i].min); 154 | } 155 | b->count = 0; 156 | } 157 | 158 | static inline void 159 | bench_free(void) 160 | { 161 | free(benchInternal.records); 162 | } 163 | 164 | 165 | static inline uint64_t 166 | bench_hash64(uint64_t x) 167 | { 168 | x ^= x >> 30; 169 | x *= 0xBF58476D1CE4E5B9u; 170 | x ^= x >> 27; 171 | x *= 0x94D049BB133111EBu; 172 | x ^= x >> 31; 173 | return x; 174 | } 175 | 176 | #define BENCH_H_INCLUDED 177 | #endif 178 | 179 | /* 180 | * Example: 181 | */ 182 | 183 | #ifdef BENCH_EXAMPLE 184 | 185 | #include 186 | #include 187 | 188 | int 189 | main(void) 190 | { 191 | size_t i; 192 | BENCH("sum", 8, 64) { 193 | unsigned int sum = 0; 194 | for (i = 0; i < 1024*16u; ++i) { 195 | sum += i; 196 | BENCH_VOLATILE_REG(sum); 197 | } 198 | } 199 | BENCH("product", 8, 64) { 200 | unsigned char sum = 0; 201 | for (i = 0; i < 1024*16u; ++i) { 202 | sum *= i; 203 | BENCH_VOLATILE_REG(sum); 204 | } 205 | } 206 | bench_done(); 207 | return 0; 208 | } 209 | 210 | #endif /* BENCH_EXAMPLE */ 211 | 212 | /* 213 | * Copyright (c) 2022 Olaf Berstein 214 | * Permission is hereby granted, free of charge, to any person obtaining a copy 215 | * of this software and associated documentation files (the "Software"), to deal 216 | * in the Software without restriction, including without limitation the rights 217 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 218 | * copies of the Software, and to permit persons to whom the Software is 219 | * furnished to do so, subject to the following conditions: 220 | * The above copyright notice and this permission notice shall be included in 221 | * all copies or substantial portions of the Software. 222 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 223 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 224 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 225 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 226 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 227 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 228 | * SOFTWARE. 229 | */ 230 | 231 | -------------------------------------------------------------------------------- /cauldron/random-xoroshiro128-jump.h: -------------------------------------------------------------------------------- 1 | 2 | static uint64_t const prng64_xoroshiro128Jump2Pow[128][2] = { 3 | { 0, 0 }, /* 0 -- 24-16-37 */ 4 | { 0, 0 }, /* 1 -- 24-16-37 */ 5 | { 0, 0 }, /* 2 -- 24-16-37 */ 6 | { 0, 0 }, /* 3 -- 24-16-37 */ 7 | { 0, 0 }, /* 4 -- 24-16-37 */ 8 | { 0, 0 }, /* 5 -- 24-16-37 */ 9 | { 0, 0 }, /* 6 -- 24-16-37 */ 10 | { 0x095B8F76579AA001, 0x0008828E513B43D5 }, /* 7 -- 24-16-37 */ 11 | { 0x162AD6EC01B26EAE, 0x7A8FF5B1C465A931 }, /* 8 -- 24-16-37 */ 12 | { 0xB4FBAA5C54EE8B8F, 0xB18B0D36CD81A8F5 }, /* 9 -- 24-16-37 */ 13 | { 0x1207A1706BEBB202, 0x23AC5E0BA1CECB29 }, /* 10 -- 24-16-37 */ 14 | { 0x2C88EF71166BC53D, 0xBB18E9C8D463BB1B }, /* 11 -- 24-16-37 */ 15 | { 0xC3865BB154E9BE10, 0xE3FBE606EF4E8E09 }, /* 12 -- 24-16-37 */ 16 | { 0x1A9FC99FA7818274, 0x28FAAAEBB31EE2DB }, /* 13 -- 24-16-37 */ 17 | { 0x588ABD4C2CE2BA80, 0x30A7C4EEF203C7EB }, /* 14 -- 24-16-37 */ 18 | { 0x9C90DEBC053E8CEF, 0xA425003F3220A91D }, /* 15 -- 24-16-37 */ 19 | { 0xB82CA99A09A4E71E, 0x81E1DD96586CF985 }, /* 16 -- 24-16-37 */ 20 | { 0x35D69E118698A31D, 0x4F7FD3DFBB820BFB }, /* 17 -- 24-16-37 */ 21 | { 0x49613606C466EFD3, 0xFEE2760EF3A900B3 }, /* 18 -- 24-16-37 */ 22 | { 0xBD031D011900A9E5, 0xF0DF0531F434C57D }, /* 19 -- 24-16-37 */ 23 | { 0x235E761B3B378590, 0x442576715266740C }, /* 20 -- 24-16-37 */ 24 | { 0x3710A7AE7945DF77, 0x1E8BAE8F680D2B35 }, /* 21 -- 24-16-37 */ 25 | { 0x75D8E7DBCEDA609C, 0xFD7027FE6D2F6764 }, /* 22 -- 24-16-37 */ 26 | { 0xDE2CBA60CD3332B5, 0x28EFF231AD438124 }, /* 23 -- 24-16-37 */ 27 | { 0x377E64C4E80A06FA, 0x1808760D0A0909A1 }, /* 24 -- 24-16-37 */ 28 | { 0x0CF0A2225DA7FB95, 0xB9A362FAFEDFE9D2 }, /* 25 -- 24-16-37 */ 29 | { 0x2BAB58A3CADFC0A3, 0xF57881AB117349FD }, /* 26 -- 24-16-37 */ 30 | { 0x8D51ECDB9ED82455, 0x849272241425C996 }, /* 27 -- 24-16-37 */ 31 | { 0x521B29D0A57326C1, 0xF1CCB8898CBC07CD }, /* 28 -- 24-16-37 */ 32 | { 0xFBE65017ABEC72DD, 0x61179E44214CAAFA }, /* 29 -- 24-16-37 */ 33 | { 0x6C446B9BC95C267B, 0xD9AA6B1E93FBB6E4 }, /* 30 -- 24-16-37 */ 34 | { 0x64F80248D23655C6, 0x86E3772194563F6D }, /* 31 -- 24-16-37 */ 35 | { 0xFAD843622B252C78, 0xD4E95EEF9EDBDBC6 }, /* 32 -- 24-16-37 */ 36 | { 0x598742BBFDDDE630, 0x05667023C584A68A }, /* 33 -- 24-16-37 */ 37 | { 0x3A9D7DCE072134A6, 0x401AACF87A5E21EE }, /* 34 -- 24-16-37 */ 38 | { 0xF0CC32EAF522F0E0, 0xE114B1E65A950E43 }, /* 35 -- 24-16-37 */ 39 | { 0xEB2BEAA80D3FD8A7, 0x905DFF85834FB8D1 }, /* 36 -- 24-16-37 */ 40 | { 0x61F29536E1BB6B99, 0xC449C069734817CB }, /* 37 -- 24-16-37 */ 41 | { 0x390CD235D35187DA, 0x1E5BC0FE7032F3DF }, /* 38 -- 24-16-37 */ 42 | { 0x744E5F1168BA3345, 0x3F399E6F1EA22DBC }, /* 39 -- 24-16-37 */ 43 | { 0x8CC9AA88A153F5F8, 0xD47A02636F041CCA }, /* 40 -- 24-16-37 */ 44 | { 0x08D037056C80B9E0, 0xF83C06B106D3B7AB }, /* 41 -- 24-16-37 */ 45 | { 0x4CE3C123D196BF7A, 0x14223EEDAE116A83 }, /* 42 -- 24-16-37 */ 46 | { 0xB1B206870DA4E89A, 0x24BFD164204335AE }, /* 43 -- 24-16-37 */ 47 | { 0x207BB2453717CF67, 0x4A5953C8F4BC2A51 }, /* 44 -- 24-16-37 */ 48 | { 0xA14E342BB11FF7E6, 0xF6B3F196DC551CCF }, /* 45 -- 24-16-37 */ 49 | { 0x5422BCA5015DD3B7, 0x5B6233B76FA214D7 }, /* 46 -- 24-16-37 */ 50 | { 0xEDE7341C00C65B85, 0xF20D7136458BD924 }, /* 47 -- 24-16-37 */ 51 | { 0xD769CFC9028DEB78, 0x9B19BA6B3752065A }, /* 48 -- 24-16-37 */ 52 | { 0xC7B0E531ABE7E4BD, 0x4F27796502238C48 }, /* 49 -- 24-16-37 */ 53 | { 0x1C6D3BA4BB94182A, 0xB7B17DCD25003305 }, /* 50 -- 24-16-37 */ 54 | { 0x3AE9471D0E2D0BCF, 0xAAAE579366147D07 }, /* 51 -- 24-16-37 */ 55 | { 0x8F9CD3794CA46FBF, 0x0D56BB288C661CCF }, /* 52 -- 24-16-37 */ 56 | { 0xDB2AD4E9C15A9D4E, 0x0402342EEDFF424C }, /* 53 -- 24-16-37 */ 57 | { 0x79E061AF5BE21395, 0x4E71559E6D0E7F00 }, /* 54 -- 24-16-37 */ 58 | { 0x96E7D88C0794E785, 0x8367AF1C9D6C1406 }, /* 55 -- 24-16-37 */ 59 | { 0xCCDDA809DB64B3E7, 0x0DBFCD2453D1D33F }, /* 56 -- 24-16-37 */ 60 | { 0x6C64681C21CD0286, 0x3309E57F180D4FF6 }, /* 57 -- 24-16-37 */ 61 | { 0xACB8D4C6BA67113E, 0xB439F330AB3B9715 }, /* 58 -- 24-16-37 */ 62 | { 0xBAD04CA5D96E2CD3, 0xC58F079D0205BCF3 }, /* 59 -- 24-16-37 */ 63 | { 0xEBFBC2723A906760, 0x09417D8C80A37AA7 }, /* 60 -- 24-16-37 */ 64 | { 0x38AC01316167183D, 0x52F51AC639E09712 }, /* 61 -- 24-16-37 */ 65 | { 0x7A134006D4EFA484, 0xF37EAD6EA53B96BA }, /* 62 -- 24-16-37 */ 66 | { 0x351561E58F8572D4, 0xDC1C01799CB8D734 }, /* 63 -- 24-16-37 */ 67 | { 0xDF900294D8F554A5, 0x170865DF4B3201FC }, /* 64 -- 24-16-37 */ 68 | { 0x2992EAD4972EAED2, 0xB2A7B279A8CB1F50 }, /* 65 -- 24-16-37 */ 69 | { 0xC026A7D9E04A7700, 0xE7859C665BE57882 }, /* 66 -- 24-16-37 */ 70 | { 0xB4CB6197DEA2B1FE, 0x4B4A7AA8C389701C }, /* 67 -- 24-16-37 */ 71 | { 0x0DCFC5B909E7DF4D, 0xADB7753D55646EEF }, /* 68 -- 24-16-37 */ 72 | { 0x468431669864F789, 0xC80926301806A352 }, /* 69 -- 24-16-37 */ 73 | { 0x22B6C1736285FCC8, 0xC05DA051EC96AF1D }, /* 70 -- 24-16-37 */ 74 | { 0x74C1DAAC8729D8BB, 0xF88F6BAC8FD30448 }, /* 71 -- 24-16-37 */ 75 | { 0x847757C126B23E45, 0x752B98D002C408F7 }, /* 72 -- 24-16-37 */ 76 | { 0x0F9EAA62D0C9E2A3, 0x1AA7BC96DBACE110 }, /* 73 -- 24-16-37 */ 77 | { 0x7475D71B98314377, 0xC469B29353A4984B }, /* 74 -- 24-16-37 */ 78 | { 0xBBB7D266D61C85EA, 0x4B6DD41BCE3BB499 }, /* 75 -- 24-16-37 */ 79 | { 0xC419B3742570E16F, 0xE023777E70B3A2F8 }, /* 76 -- 24-16-37 */ 80 | { 0x2A71DB3A3CE8B968, 0x131E94FB35203D80 }, /* 77 -- 24-16-37 */ 81 | { 0x2897BB8961B4DCE9, 0x9240C95B1E7FA08B }, /* 78 -- 24-16-37 */ 82 | { 0xF0FC3553D7881D5F, 0xB879FCA0915F893F }, /* 79 -- 24-16-37 */ 83 | { 0xE754DB3FBC7536BC, 0x2ADCA86FBEFE1366 }, /* 80 -- 24-16-37 */ 84 | { 0x0A9E201ADFE7BAA9, 0x0A40A688D77855BA }, /* 81 -- 24-16-37 */ 85 | { 0x1D0D601E49C35837, 0x17771C905E0775A8 }, /* 82 -- 24-16-37 */ 86 | { 0x9B031395AEC7B584, 0x2CF775E419A607E0 }, /* 83 -- 24-16-37 */ 87 | { 0x79EAD2EEDDF66699, 0x93A7CF27DEC9B306 }, /* 84 -- 24-16-37 */ 88 | { 0xE1B9805C107679FC, 0x93615189FE85B7D5 }, /* 85 -- 24-16-37 */ 89 | { 0x2C3925DCD790E3D6, 0x466421124B50FBFB }, /* 86 -- 24-16-37 */ 90 | { 0xDCA9B0FA4E95600E, 0x1CDA7BD04E3BB94B }, /* 87 -- 24-16-37 */ 91 | { 0xEFC7905E1CBB5FFB, 0x5EC431D73BBFE49F }, /* 88 -- 24-16-37 */ 92 | { 0x854414811D534483, 0x31A1F85FD532F302 }, /* 89 -- 24-16-37 */ 93 | { 0xADB9BA2958F30B6E, 0xED9B991C09177E2F }, /* 90 -- 24-16-37 */ 94 | { 0x76F8FDF26B0D1CBB, 0x38D9E87DFFDFCA70 }, /* 91 -- 24-16-37 */ 95 | { 0x51F21CDDCEBDB8C7, 0xD8E9E7254052AF4D }, /* 92 -- 24-16-37 */ 96 | { 0xA03F796EFB295305, 0x62769780D13FBC08 }, /* 93 -- 24-16-37 */ 97 | { 0x4F2083F6B19E628A, 0x66E5456C2EAEDBFF }, /* 94 -- 24-16-37 */ 98 | { 0x8B2BE9CD79734BED, 0xACE8D6CE8E3FBA17 }, /* 95 -- 24-16-37 */ 99 | { 0xD2A98B26625EEE7B, 0xDDDF9B1090AA7AC1 }, /* 96 -- 24-16-37 */ 100 | { 0x4FFF128094EDD94C, 0x00D67DC46AD28695 }, /* 97 -- 24-16-37 */ 101 | { 0x726438E9A1D3C6EA, 0xF9540570703E7CF3 }, /* 98 -- 24-16-37 */ 102 | { 0x92CC6A0937C9D34E, 0x066A9599766619B5 }, /* 99 -- 24-16-37 */ 103 | { 0xC5730DE058E1047F, 0xA4E540C7AC49AA1B }, /* 100 -- 24-16-37 */ 104 | { 0xE408BBECDA066551, 0xC2EDFC1AB51C00AD }, /* 101 -- 24-16-37 */ 105 | { 0xC5477EA8821CE588, 0xF11753A4339E78C3 }, /* 102 -- 24-16-37 */ 106 | { 0x3C6058E633063180, 0xBB42E906EFB12540 }, /* 103 -- 24-16-37 */ 107 | { 0xBEC40E0518086E21, 0x4E86F36C495EEEDB }, /* 104 -- 24-16-37 */ 108 | { 0x465276434FD98954, 0xE8345A7C487FEFD6 }, /* 105 -- 24-16-37 */ 109 | { 0x3ADAEA5CDFE12E3B, 0x688B762874221434 }, /* 106 -- 24-16-37 */ 110 | { 0xC9DFFA95904E99B1, 0x833801923A05F253 }, /* 107 -- 24-16-37 */ 111 | { 0xA10C3FB0B18DF787, 0x58A00D23A8086646 }, /* 108 -- 24-16-37 */ 112 | { 0xA4E41F760281C3D0, 0xEC69708D487DBFC4 }, /* 109 -- 24-16-37 */ 113 | { 0xB8880FFF0E41261C, 0x47176F17DE7FF0E9 }, /* 110 -- 24-16-37 */ 114 | { 0x58EE3B30F542767E, 0x4F40C533643920EA }, /* 111 -- 24-16-37 */ 115 | { 0x15F2D25B60C5ACD7, 0x83FD48D6B9620584 }, /* 112 -- 24-16-37 */ 116 | { 0xE448C83950A687EA, 0x0CE303C7D3AABBC8 }, /* 113 -- 24-16-37 */ 117 | { 0xA6FF7863C363CFD4, 0x1746715DF0DD8FE3 }, /* 114 -- 24-16-37 */ 118 | { 0x7E9D8517B195D9C9, 0xC00185964CAEF8BB }, /* 115 -- 24-16-37 */ 119 | { 0x40DDB4DAF3FBDDA8, 0xB6BDE02BD004B144 }, /* 116 -- 24-16-37 */ 120 | { 0x7A794B820672A49B, 0xBA43C63EC5A9F187 }, /* 117 -- 24-16-37 */ 121 | { 0xC1BE31E7536236FB, 0x2467071B1D261621 }, /* 118 -- 24-16-37 */ 122 | { 0xF0EEC34DAEA486FB, 0x5A6FC0435F011DAA }, /* 119 -- 24-16-37 */ 123 | { 0xF42C01A2A3815DB4, 0xA5AF34331C044D81 }, /* 120 -- 24-16-37 */ 124 | { 0xDF7964C343B312DE, 0xDB43B553CD16EA44 }, /* 121 -- 24-16-37 */ 125 | { 0x8454182464C29903, 0x432C2BBCD03E65F6 }, /* 122 -- 24-16-37 */ 126 | { 0x7B6C0ECC6CB5ADBB, 0xCDF56412D1E7BA6E }, /* 123 -- 24-16-37 */ 127 | { 0x380B97764C9F7748, 0xAC13C8B2FF838036 }, /* 124 -- 24-16-37 */ 128 | { 0x1868A9F5A4FD4D64, 0x71D208CC2E5C56E9 }, /* 125 -- 24-16-37 */ 129 | { 0xE89F5FE075D74A79, 0xD1D08A01B73DE005 }, /* 126 -- 24-16-37 */ 130 | { 0x25AA87F3C2704C69, 0xA9495C12936AD0FD }, /* 127 -- 24-16-37 */ 131 | }; 132 | -------------------------------------------------------------------------------- /tools/random/permute/evalpow2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define RANDOM_H_IMPLEMENTATION 14 | #include 15 | #include 16 | 17 | 18 | /* Based on https://github.com/skeeto/hash-prospector */ 19 | 20 | 21 | #define SQRT_OF_PI_OVER_TWO 0.79788456080286535589 22 | 23 | /* Measures how each input bit affects each output bit. 24 | * This measures both bias and avalanche. */ 25 | static double 26 | estimate_bias(uint64_t (*hash)(uint64_t i, uint64_t mask, uint64_t seed), 27 | int bits, int quality, int seedEvalRange, double *avrHashTime) 28 | { 29 | /* We treat the index and the seed together as the input. */ 30 | uint64_t bins[128][64] = {{0}}; 31 | int64_t const n = UINT64_C(1) << quality; 32 | uint64_t const mask = (bits == 64) ? UINT64_MAX : (UINT64_C(1) << bits) - 1; 33 | uint64_t ns = 0; 34 | double mean = 0; 35 | 36 | #pragma omp parallel 37 | { 38 | PRNG64RomuQuad rng; 39 | prng64_romu_quad_randomize(&rng); 40 | 41 | struct timespec beg, end; 42 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &beg); 43 | 44 | #pragma omp for reduction(+:bins[:128][:64]) 45 | for (int64_t i = 0; i < n; ++i) { 46 | uint64_t seed = prng64_romu_quad(&rng); 47 | uint64_t x = prng64_romu_quad(&rng) & mask; 48 | uint64_t h0 = hash(x, mask, seed); 49 | 50 | /* evaluate seed changes */ 51 | for (int j = 0; j < seedEvalRange; ++j) { 52 | uint64_t bit = UINT64_C(1) << j; 53 | uint64_t h1 = hash(x, mask, seed ^ bit); 54 | uint64_t set = h0 ^ h1; 55 | for (int k = 0; k < bits; ++k) 56 | bins[j][k] += (set >> k) & 1; 57 | } 58 | 59 | /* evaluate index changes */ 60 | for (int j = 0; j < bits; ++j) { 61 | uint64_t bit = UINT64_C(1) << j; 62 | uint64_t h1 = hash(x ^ bit, mask, seed); 63 | uint64_t set = h0 ^ h1; 64 | for (int k = 0; k < bits; ++k) 65 | bins[j + seedEvalRange][k] += (set >> k) & 1; 66 | } 67 | } 68 | 69 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); 70 | 71 | #pragma omp atomic 72 | ns += (end.tv_sec - beg.tv_sec) * 1000000000 + (end.tv_nsec - beg.tv_nsec); 73 | } 74 | 75 | *avrHashTime = (double)ns / (n * (1 + seedEvalRange + bits)); 76 | 77 | for (int j = 0; j < bits + seedEvalRange; ++j) { 78 | for (int k = 0; k < bits; ++k) { 79 | double diff = (bins[j][k] - n/2.0) / n; 80 | mean += fabs(diff); 81 | } 82 | } 83 | 84 | return mean * 1000.0 / ((bits + seedEvalRange) * bits); 85 | } 86 | 87 | static void 88 | die(char *fmt, ...) 89 | { 90 | va_list args; 91 | va_start(args, fmt); 92 | vfprintf(stderr, fmt, args); 93 | va_end(args); 94 | exit(EXIT_FAILURE); 95 | } 96 | 97 | static void 98 | usage(char *argv0) 99 | { 100 | printf("usage: %s [OPTION...] \n", argv0); 101 | puts("Evaluates the bias of a hash function that is invertible for a"); 102 | puts("given power-of-two sized domain.\n"); 103 | 104 | puts("One of the following option is required:"); 105 | puts(" -b, --best output the theoretically best bias possible"); 106 | puts(" -l, --load=lib.so the following function prototype is loaded from lib.so:"); 107 | puts(" uint64_t hash(uint64_t i, uint64_t mask, uint64_t seed)"); 108 | 109 | puts("Seed bias: (default: -f)"); 110 | puts(" -0, --eval-none don't evaluate seed bias"); 111 | puts(" -c, --eval-current evaluate seed bias only up to the current power-of-two"); 112 | puts(" -f, --eval-full evaluate full seed bias "); 113 | 114 | puts("Other options:"); 115 | puts(" -n, --num-bits=N number of bits used by the hash (default: 32)"); 116 | puts(" -o, --output=FILE write the biases into a csv FILE"); 117 | puts(" -q, --quality=N evaluation 2^N hashes per power-of-two"); 118 | puts(" (12-30, default: 18)"); 119 | puts(" -s, --start=N test all powers-of-two stating from 2^N"); 120 | puts(" (default: 1)"); 121 | puts(" -S, --stop=N test all powers-of-two up to 2^N"); 122 | puts(" (default: --num-bits)"); 123 | puts(" -v, --verbose print the bias for every power-of-two tested"); 124 | puts(" -?, -h, --help display this help and exit"); 125 | } 126 | 127 | int 128 | main(int argc, char **argv) 129 | { 130 | char *argv0 = argv[0]; 131 | 132 | /* obligatory options */ 133 | int printBest = 0; 134 | char *sofile = 0; 135 | 136 | /* options */ 137 | FILE *output = 0; 138 | enum { 139 | SEED_EVAL_NONE, 140 | SEED_EVAL_CURRENT, 141 | SEED_EVAL_FULL 142 | } seedEvalType = SEED_EVAL_FULL; 143 | int nbits = 32; 144 | int quality = 18; 145 | int start = 1; 146 | int stop = 0; 147 | int stopset = 0; 148 | int verbose = 0; 149 | uint64_t (*hash)(uint64_t i, uint64_t mask, uint64_t seed) = 0; 150 | 151 | /* parse arguments */ 152 | ARG_BEGIN { 153 | if (ARG_LONG("best")) case 'b': { 154 | printBest = 1; 155 | sofile = 0; 156 | ARG_FLAG(); 157 | } else if (ARG_LONG("load")) case 'l': { 158 | sofile = ARG_VAL(); 159 | printBest = 0; 160 | } else if (ARG_LONG("eval-none")) case '0': { 161 | seedEvalType = SEED_EVAL_NONE; 162 | ARG_FLAG(); 163 | } else if (ARG_LONG("eval-current")) case 'c': { 164 | seedEvalType = SEED_EVAL_CURRENT; 165 | ARG_FLAG(); 166 | } else if (ARG_LONG("num-bits")) case 'n': { 167 | nbits = atoi(ARG_VAL()); 168 | } else if (ARG_LONG("output")) case 'o': { 169 | if (!(output = fopen(ARG_VAL(), "w"))) 170 | die("%s: couldn't create file '%s'\n", 171 | argv0, ARG_VAL()); 172 | } else if (ARG_LONG("quality")) case 'q': { 173 | quality = atoi(ARG_VAL()); 174 | } else if (ARG_LONG("start")) case 's': { 175 | start = atoi(ARG_VAL()); 176 | } else if (ARG_LONG("stop")) case 'S': { 177 | stop = atoi(ARG_VAL()); 178 | stopset = 1; 179 | } else if (ARG_LONG("verbose")) case 'v': { 180 | verbose = 1; 181 | ARG_FLAG(); 182 | } else if (ARG_LONG("help")) case 'h': case '?': { 183 | usage(argv0); 184 | return EXIT_SUCCESS; 185 | } else default: { 186 | die("%s: invalid option '%s'\n" 187 | "Try '%s --help' for more information.\n", 188 | argv0, *argv, argv0); 189 | } 190 | } ARG_END; 191 | 192 | if (quality < 12 || quality > 30) 193 | die("%s: quality out of range, expected " 194 | "12 to 30, got '%d'\n", argv0, quality); 195 | 196 | stop = (stopset) ? stop : nbits; 197 | 198 | if (stop < start || stop > nbits) 199 | die("%s: quality out of range, expected " 200 | "1 to %d, got '%d'\n", argv0, nbits, quality); 201 | 202 | if (start < 1 || start > stop) 203 | die("%s: quality out of range, expected " 204 | "1 to %d, got '%d'\n", argv0, nbits, quality); 205 | 206 | 207 | if (argc != 0 || argv[0] || (!sofile && !printBest)) { 208 | usage(argv0); 209 | return EXIT_FAILURE; 210 | } 211 | 212 | if (printBest) { 213 | double n = UINT64_C(1) << quality; 214 | double variance = sqrt(n*0.5*0.5); 215 | double foldedVariance = variance*SQRT_OF_PI_OVER_TWO; 216 | double bias = foldedVariance/n * 1000.0; 217 | 218 | double totalBias = 0; 219 | 220 | for (int i = start; i <= stop; ++i) { 221 | if (verbose) 222 | printf("bias[%d] = %.17g\n", i, bias); 223 | if (output) 224 | fprintf(output, "%d,%.17g\n", i, bias); 225 | totalBias += bias; 226 | } 227 | if (output) 228 | fclose(output); 229 | 230 | printf("\ntotal bias = %.17g\n", totalBias); 231 | printf("avr bias = %.17g\n", totalBias / (stop - start + 1)); 232 | 233 | return EXIT_SUCCESS; 234 | } 235 | 236 | /* load hash from sofile */ 237 | if (sofile) { 238 | void *handle; 239 | if (!(handle = dlopen(sofile, RTLD_NOW))) 240 | die("%s: couldn't load shared object file '%s'\n", argv0, sofile); 241 | if (!(hash = dlsym(handle, "hash"))) 242 | die("%s: couldn't find the symbol 'hash' in '%s'\n", argv0, sofile); 243 | } 244 | 245 | /* evaluate bias of hashes */ 246 | { 247 | double totalBias = 0; 248 | double avrHashTime = 0; 249 | 250 | 251 | for (int i = start; i <= stop; ++i) { 252 | int range; 253 | switch (seedEvalType) { 254 | case SEED_EVAL_NONE: range = 0; break; 255 | case SEED_EVAL_CURRENT: range = i; break; 256 | case SEED_EVAL_FULL: range = nbits; break; 257 | } 258 | double t, bias = estimate_bias( 259 | hash, i, quality, range, &t); 260 | avrHashTime += t / nbits; 261 | if (verbose) { 262 | printf("bias[%d] = %.17g\n", i, bias); 263 | } else { 264 | printf("\r%d/%d", i - start, stop - start + 1); 265 | fflush(stdout); 266 | } 267 | if (output) { 268 | fprintf(output, "%d,%.17g\n", i, bias); 269 | fflush(output); /* so we can see the progress */ 270 | } 271 | totalBias += bias; 272 | } 273 | if (output) 274 | fclose(output); 275 | 276 | printf("\ntotal bias = %.17g\n", totalBias); 277 | printf("avr bias = %.17g\n", totalBias / (stop - start + 1)); 278 | printf("speed = %.3f ns / hash\n", avrHashTime); 279 | } 280 | 281 | return 0; 282 | } 283 | -------------------------------------------------------------------------------- /tools/random/permute/README.md: -------------------------------------------------------------------------------- 1 | # Improving Andrew Kensler's permute(): 2 | ## A function for stateless, constant-time pseudorandom-order array iteration 3 | 4 | I recently came across a rather fascinating [blog post](https://andrew-helmer.github.io/permute/) from Andrew Helmer. 5 | It explains the permute() function, introduced in a [paper](https://graphics.pixar.com/library/MultiJitteredSampling/paper.pdf) written by Andrew Kensler. 6 | 7 | I really recommend that you quickly take the time to read this [blog post](https://andrew-helmer.github.io/permute/), but I'll give a quick summary of it here anyways: 8 | 9 | permute() is a stateless and constant-time function that generates unique pseudorandom permutations for a given seed. It works using a hash function that is invertible for a given power-of-two size domain, which implies that there is a one to one mapping for all numbers in the range `[0:(2^n)-1]`. This means that if you pass any number in the range `[0:(2^n)-1]` to the hash function it will always return a unique number that is also in the same range. To get this to work with arbitrary ranges, we can use so-called "cycle walking", which entails rounding up our desired range to the next power-of-two and discarding every number that isn't within the range. 10 | 11 | I already knew of two other similar algorithms, using a [weyl sequence](https://en.wikipedia.org/wiki/Weyl_sequence) or a [LCG](https://en.wikipedia.org/wiki/Linear_congruential_generator) with a modulo of the next power-of-two, but those approaches aren't very random and the underlying generators very easily fail statistical testing. 12 | This is where I wasn't satisfied with the information from the paper, as they never supplied any measurements of the quality of randomness. They only said that they found a hash function with good avalanche properties and that they had good results with ranges up to `2^27`. 13 | 14 | Luckily you should be able to make invertible hash functions as high quality as you want to, by just adding more and more operations, so I set out to test the randomness of the original hash function. 15 | I also wanted to find a suitable 64-bit hash function since the advantages of using something like permute() are bigger with larger ranges. 16 | 17 | 18 | ### A better (64-bit) function 19 | 20 | Before I go over how the testing was done I'm going to quickly present my new and improved hash function, so we can directly look at the test results later. 21 | 22 | I started out with Kensler's original hash functions and tried to improve on it, by adding other well known high-quality invertible integer hash functions. 23 | 24 |
25 | kensler.c 26 |

27 | 28 | ```c 29 | uint32_t 30 | hash(uint32_t idx, uint32_t mask, uint32_t seed) 31 | { 32 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 33 | idx ^= seed; idx *= 0xe170893d; 34 | idx ^= seed >> 16; 35 | idx ^= (idx & mask) >> 4; 36 | idx ^= seed >> 8; idx *= 0x0929eb3f; 37 | idx ^= seed >> 23; 38 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 39 | idx *= 0x6935fa69; 40 | idx ^= (idx & mask) >> 11; idx *= 0x74dcb303; 41 | idx ^= (idx & mask) >> 2; idx *= 0x9e501cc3; 42 | idx ^= (idx & mask) >> 2; idx *= 0xc860a3df; 43 | idx &= mask; 44 | idx ^= idx >> 5; 45 | return (idx ^ seed) & mask; 46 | } 47 | ``` 48 | 49 |

50 |
51 | 52 | As a baseline, for testing, I used the original 32-bit hash and a 64-bit hash, that combines the original with an adapted version of the well known 64-bit hash function `splittable64`. 53 | 54 |
55 | kensler-splittable64.c 56 |

57 | 58 | ```c 59 | uint64_t 60 | hash(uint64_t idx, uint64_t mask, uint64_t seed) 61 | { 62 | idx ^= seed; 63 | /* splittable64 */ 64 | idx ^= (idx & mask) >> 30; idx *= UINT64_C(0xBF58476D1CE4E5B9); 65 | idx ^= (idx & mask) >> 27; idx *= UINT64_C(0x94D049BB133111EB); 66 | idx ^= (idx & mask) >> 31; 67 | idx *= UINT64_C(0xBF58476D1CE4E5B9); 68 | 69 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 70 | idx ^= seed; idx *= 0xe170893d; 71 | idx ^= seed >> 16; 72 | idx ^= (idx & mask) >> 4; 73 | idx ^= seed >> 8; idx *= 0x0929eb3f; 74 | idx ^= seed >> 23; 75 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 76 | idx *= 0x6935fa69; 77 | idx ^= (idx & mask) >> 11; idx *= 0x74dcb303; 78 | idx ^= (idx & mask) >> 2; idx *= 0x9e501cc3; 79 | idx ^= (idx & mask) >> 2; idx *= 0xc860a3df; 80 | idx &= mask; 81 | idx ^= idx >> 5; 82 | return idx; 83 | } 84 | ``` 85 | 86 |

87 |
88 | 89 | Then I used the tests below to evaluate different combinations of hash functions, which culminated in the following hash function: 90 | 91 |
92 | camel-cdr.c 93 |

94 | 95 | ```c 96 | uint64_t 97 | hash(uint64_t idx, uint64_t mask, uint64_t seed) 98 | { 99 | idx ^= seed; 100 | /* splittable64 */ 101 | idx ^= (idx & mask) >> 30; idx *= UINT64_C(0xBF58476D1CE4E5B9); 102 | idx ^= (idx & mask) >> 27; idx *= UINT64_C(0x94D049BB133111EB); 103 | idx ^= (idx & mask) >> 31; 104 | idx *= UINT64_C(0xBF58476D1CE4E5B9); 105 | 106 | idx ^= seed >> 32; 107 | idx *= UINT32_C(0xED5AD4BB); 108 | 109 | idx ^= seed >> 48; 110 | /* hash16_xm3 */ 111 | idx ^= (idx & mask) >> 7; idx *= 0x2993u; 112 | idx ^= (idx & mask) >> 5; idx *= 0xE877u; 113 | idx ^= (idx & mask) >> 9; idx *= 0x0235u; 114 | idx ^= idx >> 10; 115 | 116 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 117 | idx ^= seed; idx *= 0xe170893d; 118 | idx ^= seed >> 16; 119 | idx ^= (idx & mask) >> 4; 120 | idx ^= seed >> 8; idx *= 0x0929eb3f; 121 | idx ^= seed >> 23; 122 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 123 | idx *= 0x6935fa69; 124 | idx ^= (idx & mask) >> 11; idx *= 0x74dcb303; 125 | idx ^= (idx & mask) >> 2; idx *= 0x9e501cc3; 126 | idx ^= (idx & mask) >> 2; idx *= 0xc860a3df; 127 | idx &= mask; 128 | idx ^= idx >> 5; 129 | 130 | return idx; 131 | } 132 | 133 | ``` 134 | 135 |

136 |
137 | 138 | 139 | ### Testing possible hash functions 140 | 141 | We can safely ignore the cycle walking when testing the randomness of permutations. If a power-of-two permutation is stably random rejecting values from it won't make it less random. In the following, we'll thus only talk about power-of-two ranges. 142 | 143 | 144 | #### Using a PractRand 145 | 146 | The best way to test anything related to pseudorandom number generation is to use one of the existing statistical test suites. I'm using the PractRand test suite since it has high-quality tests and has a nice commanding interface. 147 | Such test suites take the output of an RNG as input, and they then try to find statistical correlations in the generated numbers. 148 | 149 | We can't just output the generated indices directly, since those are always unique for a range. This would lead to correlations since once a number occurs it doesn't occur again until all numbers in the range were generated and this could/should be picked up by the test suite. 150 | To circumvent this we can create an array of random elements, sort this array and then output a random permutation of the sorted array. The original approach of outputting the indices directly would be equivalent to indexing an array that contains consecutive numbers from `0` to `n`. The initial random initialization of the elements removes the bias we had earlier. Note that the elements of the array should have a smaller range than the size of the array, hence we'll be an array of bytes. 151 | 152 | `PractRand` evaluates the quality for every power-of-two bytes of input bytes separately. 153 | I recorded on which, if any, power-of-two each hash function failed a test and ran each hash function with a powers-of-two against `PractRand stdin8 -tf 2 -te 1`. The seeds were randomly initialized, so this does reflect the hash quality of the index but doesn't properly test how good the seed is integrated into the hash. 154 | 155 | | range [0:(2^n)-1] | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 156 | | --------------------:| ---:| ---:| ---:| ---:| ---:| ---:| ---:| ---:| ---:| ---:| ---:| 157 | | kensler | 19 | 19 | 20 | 24 | 25 | 26 | 27 | 30 | 32 | >34 | | 158 | | kensler-splittable64 | 16 | 17 | 21 | 21 | 22 | 26 | 28 | 28 | 32 | 33 | >34 | 159 | | camel-cdr | 16 | 17 | 23 | 29 | 30 | 32 | >34 | | | | | 160 | 161 | Although it initially fails a bit earlier my new hash function `camel-cdr` reaches the point, where I couldn't run the test any longer and no defects could be detected, earlier. 162 | This is already quite nice, but I wasn't able to test the larger ranges, since detecting defects through this method takes way too long. 163 | 164 | 165 | #### By calculating the hash bias 166 | 167 | Fortunately, there there is another way to evaluate the randomness: By calculating the bias of the hash function. 168 | 169 | While searching for high-quality invertible hash functions that I could combine to create a better power-of-two invertible hash function, I stumbled across another awesome [blog post](https://nullprogram.com/blog/2018/07/31/) and the corresponding [git repo](https://github.com/skeeto/hash-prospector). 170 | It is about randomly generating new hash functions and evaluating them to find hashes with a low bias. 171 | 172 | The part I was especially interested in is the way the bias is calculated. 173 | The underlying idea is that flipping a single bit in the input should flip on average 50% of the output bits. 174 | This can be evaluated by generating a bunch of random inputs, independently flipping every single input bit and counting the average number of bits that were different between the original output and the one from the input where one bit was flipped. 175 | To get this to work with the hash functions we are interested in one can also thread the seed as an input and use the same algorithm for every power of two supported by the hash. 176 | 177 | I've generated a bunch of graphs comparing the bias from the hash functions with the theoretical bias limit below. 178 | The [blog post](https://nullprogram.com/blog/2018/07/31/) didn't include the method of how the theoretical bias limit is calculated and only offered the limit for 32-bit hash functions. 179 | Doing the calculations on my own, I came to the conclusion, that the bias limit from the blog is wrong. I empirically verified this and created an [issue](https://github.com/skeeto/hash-prospector/issues/12) that proposes a working way to calculate the bias. I won't go into more detail about this here, but note that the biases calculated here can't be directly compared to the ones from the [blog post](https://nullprogram.com/blog/2018/07/31/). 180 | 181 | But now let's have a look at the graphs. 182 | The first one was generated by flipping the input bits and using a fixed random seed, to mimic what the PractRand test measured. 183 | 184 | 185 | 186 | (Generated using `./plot.sh -o 0n64q24.svg -b -0 -n 64 -q 24 candidates/camel-cdr.so candidates/kensler-splittable64.so candidates/kensler.so`) 187 | 188 | These results confirm the PractRand test results, in which my hash function passed all test with `2^24` bytes of output at a range of 2^10, the original `kensler` at 2^13 and `kensler-splittable64` at 2^14. 189 | This roughly matches the gap between the graphs marked above. 190 | 191 | Ideally, we'd like all seed bits to directly influence the output, so I also plotted the bias of flipping every seed bit in addition to every input bit. 192 | 193 | 194 | 195 | (Generated using `./plot.sh -o n${i}q22.svg -b -n $i -q 22 candidates/camel-cdr.so candidates/kensler-splittable64.so candidates/kensler.so`) 196 | 197 | For the first graph, only the first 32-bit of the seed were measured. This also confirms the claim from the [paper](https://graphics.pixar.com/library/MultiJitteredSampling/paper.pdf), that the quality degrades after `2^27`. 198 | We further learn, that the degrading already starts at `2^25` and that the quality for ranges smaller than 2^15 isn't that good either. The optimal bias is only reached for ranges from `2^23` to `2^25`. 199 | My proposed hash function also isn't perfect for smaller ranges, but it reaches the bias limit for ranges greater than `2^15` and the bias stays at the same level for all larger ranges. The second graph, for which all 64-bit of the seed were measured, shows that this trend continues to ranges up to `2^64`. 200 | We can also see that the trivial 64-bit version of the original `kensler-splittable64` isn't very good at incorporating the upper seed bits and thus only reaches the bias limit at the `2^64` range. 201 | 202 | So in conclusion the new hash function seems to have a good quality for ranges larger than `2^15`. This is actually exactly what we are looking for, because, as already mentioned, the advantages of using something like permute() are bigger with larger ranges. 203 | 204 | 205 | ### Performance comparisons 206 | 207 | | | ns/hash | 208 | | ---------------------:| ---------:| 209 | | kensler | 4.761300 | 210 | | kensler-splittable64 | 7.011112 | 211 | | camel-cdr | 11.332915 | 212 | 213 | 214 | ### A working code snippet 215 | 216 | ```c 217 | #include 218 | #include 219 | #include 220 | 221 | typedef struct { 222 | uint64_t mask, len, seed; 223 | } Permute64; 224 | 225 | void 226 | permute64_init(Permute64 *this, uint64_t len, uint64_t seed) 227 | { 228 | uint64_t mask = len-1; 229 | mask |= mask >> 1; 230 | mask |= mask >> 2; 231 | mask |= mask >> 4; 232 | mask |= mask >> 8; 233 | mask |= mask >> 16; 234 | mask |= mask >> 32; 235 | this->mask = mask; 236 | this->len = len; 237 | this->seed = seed; 238 | } 239 | 240 | uint64_t 241 | permute64(Permute64 const *this, uint64_t idx) 242 | { 243 | uint64_t const mask = this->mask; 244 | uint64_t const len = this->len; 245 | uint64_t const seed = this->seed; 246 | do { 247 | idx ^= seed; 248 | /* splittable64 */ 249 | idx ^= (idx & mask) >> 30; idx *= UINT64_C(0xBF58476D1CE4E5B9); 250 | idx ^= (idx & mask) >> 27; idx *= UINT64_C(0x94D049BB133111EB); 251 | idx ^= (idx & mask) >> 31; 252 | idx *= UINT64_C(0xBF58476D1CE4E5B9); 253 | 254 | idx ^= seed >> 32; 255 | idx &= mask; 256 | idx *= UINT32_C(0xED5AD4BB); 257 | 258 | idx ^= seed >> 48; 259 | ///* hash16_xm3 */ 260 | idx ^= (idx & mask) >> 7; idx *= 0x2993u; 261 | idx ^= (idx & mask) >> 5; idx *= 0xE877u; 262 | idx ^= (idx & mask) >> 9; idx *= 0x0235u; 263 | idx ^= (idx & mask) >> 10; 264 | 265 | /* From Andrew Kensler: "Correlated Multi-Jittered Sampling" */ 266 | idx ^= seed; idx *= 0xe170893d; 267 | idx ^= seed >> 16; 268 | idx ^= (idx & mask) >> 4; 269 | idx ^= seed >> 8; idx *= 0x0929eb3f; 270 | idx ^= seed >> 23; 271 | idx ^= (idx & mask) >> 1; idx *= 1 | seed >> 27; 272 | idx *= 0x6935fa69; 273 | idx ^= (idx & mask) >> 11; idx *= 0x74dcb303; 274 | idx ^= (idx & mask) >> 2; idx *= 0x9e501cc3; 275 | idx ^= (idx & mask) >> 2; idx *= 0xc860a3df; 276 | idx &= mask; 277 | idx ^= idx >> 5; 278 | } while (idx >= len); 279 | return idx; 280 | } 281 | 282 | int 283 | main(void) 284 | { 285 | Permute64 p; 286 | permute64_init(&p, 10, 0x5eeda628748fc822 + time(0)); 287 | 288 | for (uint64_t i = 0; i < 10; ++i) { 289 | printf("%llu\n", permute64(&p, i)); 290 | } 291 | } 292 | ``` 293 | 294 | -------------------------------------------------------------------------------- /tools/random/permute/res/0n64q24.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 17 | 19 | image/svg+xml 20 | 22 | Gnuplot 23 | 24 | 25 | 26 | 28 | 30 | 35 | 40 | 45 | 50 | 58 | 67 | 74 | 79 | 84 | 89 | 94 | 99 | 104 | 109 | 114 | 119 | 126 | 131 | 136 | 137 | 144 | 149 | 154 | 155 | 156 | 157 | Gnuplot 159 | Produced by GNUPLOT 5.4 patchlevel 1 161 | 168 | 175 | 180 | 185 | 0.01 192 | 198 | 204 | 209 | 214 | 0.1 221 | 227 | 232 | 237 | 1 244 | 250 | 255 | 260 | 10 267 | 273 | 278 | 283 | 100 290 | 296 | 301 | 1000 308 | 314 | 319 | 0 326 | 332 | 336 | 341 | 10 348 | 354 | 359 | 20 366 | 372 | 377 | 30 384 | 390 | 395 | 40 402 | 408 | 413 | 50 420 | 426 | 431 | 60 438 | 444 | 449 | 70 456 | bias 464 | 468 | 473 | bits 480 | 489 | camel-cdr 493 | 494 | 499 | 504 | 513 | best 517 | 518 | 527 | kensler-splittable64 531 | 532 | 537 | 546 | kensler 550 | 551 | 556 | ./plot.sh -b -0 -n 64 -q 24 563 | 568 | 13 575 | 576 | -------------------------------------------------------------------------------- /test/random/dist_normal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * A modified version of Jochen Voss testgaus.c, the orginial can be found at 3 | * https://www.seehuhn.de/pages/ziggurat.html. 4 | * 5 | * testgauss.c - statistical tests for gaussian random numbers 6 | * 7 | * Copyright (C) 2005 Jochen Voss. 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | * 23 | * $Id: testgauss.c 6509 2005-07-07 18:31:10Z voss $ 24 | */ 25 | 26 | #define _USE_MATH_DEFINES 27 | #define RANDOM_H_IMPLEMENTATION 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | static PRNG32RomuQuad prng32; 34 | static PRNG64RomuQuad prng64; 35 | static DistNormalfZig zigf; 36 | static DistNormalZig zig; 37 | 38 | static double f_dist_normalf(void) 39 | { return dist_normalf(prng32_romu_quad, &prng32); } 40 | static double f_dist_normal(void) 41 | { return dist_normal(prng64_romu_quad, &prng64); } 42 | static double f_dist_normalf_zig(void) 43 | { return dist_normalf_zig(&zigf, prng32_romu_quad, &prng32); } 44 | static double f_dist_normal_zig(void) 45 | { return dist_normal_zig(&zig, prng64_romu_quad, &prng64); } 46 | static double f_dist_normalf_fast(void) 47 | { return dist_normalf_fast(prng64_romu_quad(&prng64)); } 48 | 49 | static void 50 | test_norm(double (*norm)(void)); 51 | 52 | 53 | int 54 | main(void) 55 | { 56 | prng32_romu_quad_randomize(&prng32); 57 | prng64_romu_quad_randomize(&prng64); 58 | dist_normalf_zig_init(&zigf); 59 | dist_normal_zig_init(&zig); 60 | 61 | #define TEST_NORM(norm) \ 62 | TEST_BEGIN((#norm)); test_norm(norm); TEST_END() 63 | 64 | TEST_NORM(f_dist_normalf); 65 | TEST_NORM(f_dist_normal); 66 | TEST_NORM(f_dist_normalf_zig); 67 | TEST_NORM(f_dist_normal_zig); 68 | TEST_NORM(f_dist_normalf_fast); 69 | 70 | return 0; 71 | } 72 | 73 | /* level of tests */ 74 | #define ALPHA 10000000000.0 75 | 76 | /* The distribution function of the standard normal distribution. */ 77 | static double 78 | Phi(double x) { return (1 + erf(x / M_SQRT2)) * 0.5; } 79 | 80 | /* the inverse of the distribution function (found by bisection) */ 81 | static double 82 | limit(double q) 83 | { 84 | double l = -1, r = 0; 85 | TEST_ASSERT(q < 0.5); 86 | while (Phi(l) > q) 87 | r = l, l -= 1; 88 | while (l + 1e-6 < r) { /* Phi(l) <= q && q < Phi(r) */ 89 | double m = 0.5 * (l + r); 90 | (Phi(m) <= q) ? (l = m) : (r = m); 91 | } 92 | return -l; 93 | } 94 | 95 | /* Return the number of iterations needed to make effects of size D visible. 96 | * T is the 1-ALPHA/2 quantile, V the variance. */ 97 | static unsigned 98 | sample_size(double t, double v, double d) 99 | { 100 | double x = t * sqrt(v) / d; 101 | TEST_ASSERT(x * x <= (double)SIZE_MAX); 102 | return x * x + 0.5; 103 | } 104 | 105 | 106 | /* test for the mean M of a gaussion distribution with known variance V. 107 | * The hypothesis is that the values are in [m-dm, m+dm]. */ 108 | static void 109 | test_mean(double m, double dm, double v, double (*f)(void)) 110 | { 111 | double s, t, d; 112 | unsigned n, steps; 113 | 114 | TEST_ASSERT(v > 0); 115 | 116 | t = limit(1.0 / ALPHA / 2); 117 | steps = sample_size(t, v, dm); 118 | s = 0; 119 | for (n = 0; n < steps; ++n) { 120 | double x = f(); 121 | s += x - m; 122 | } 123 | s /= n; 124 | d = t * sqrt(v / n); 125 | 126 | TEST_ASSERT_MSG(fabs(s) <= d, ( 127 | "\tparameter %g is outside the confidence interval [%g; %g]\n" 128 | "\tthis may be due to statistical fluctuations, so try again.\n" 129 | "\tin the long run this test should fail 1 of %f times.", 130 | m, s - d, s + d, round(ALPHA + 0.5))); 131 | } 132 | 133 | /* Test for the parameter P of a binomial distribution. */ 134 | static void 135 | test_variance(double p, double dp, unsigned (*f)(void)) 136 | { 137 | double e, s, x, t; 138 | unsigned n, k, steps; 139 | 140 | TEST_ASSERT(dp > 0); 141 | TEST_ASSERT(0 <= p - dp && p + dp <= 1); 142 | 143 | t = limit(1.0 / ALPHA / 2); 144 | steps = sample_size(t, p * (1 - p), dp); 145 | for (n = 0, k = 0; n < steps; ++n) 146 | if (f()) 147 | ++k; 148 | 149 | TEST_ASSERT(n * p * (1 - p) >= 9); 150 | e = n * p; 151 | s = sqrt(n * p * (1 - p)); 152 | x = (k - e) / s; 153 | 154 | TEST_ASSERT_MSG(fabs(x) <= t, ( 155 | "\tParameter %g is outside the confidence interval [%g; %g]\n" 156 | "\tThis may be due to statistical fluctuations, so try again.\n" 157 | "\tIn the long run this test should fail 1 of %f times.", 158 | p, (k - t * s) / n, (k + t * s) / n, 159 | round(ALPHA + 0.5))); 160 | } 161 | 162 | static double (*distNormal)(void); 163 | 164 | static double 165 | test_norm1(void) 166 | { return distNormal() * M_SQRT2; } 167 | 168 | static unsigned 169 | test_norm2(void) 170 | { return (distNormal() * M_SQRT2) >= 1; } 171 | 172 | static unsigned 173 | test_norm3(void) 174 | { return (distNormal() * M_SQRT2) >= 3; } 175 | 176 | static double 177 | test_norm4(void) 178 | { 179 | double x1 = distNormal() * 1.09544511501; /* sqrt(1.2) */ 180 | double x2 = distNormal() * 1.67332005307; /* sqrt(2.8) */ 181 | return x1 - x2; 182 | } 183 | 184 | static unsigned 185 | test_norm5(void) 186 | { 187 | double x1 = distNormal() * 1.09544511501; /* sqrt(1.2) */ 188 | double x2 = distNormal() * 1.67332005307; /* sqrt(2.8) */ 189 | return (x1 - x2 <= -1); 190 | } 191 | 192 | static void 193 | test_norm(double (*norm)(void)) 194 | { 195 | distNormal = norm; 196 | test_mean(0, 0.03, 1, test_norm1); 197 | test_variance(0.2397500611, 0.01, test_norm2); 198 | test_variance(0.0169474268, 0.003, test_norm3); 199 | test_mean(0, 0.05, 4, test_norm4); 200 | test_variance(0.3085375387, 0.02,test_norm5); 201 | } 202 | 203 | 204 | /* 205 | * GNU GENERAL PUBLIC LICENSE 206 | * Version 2, June 1991 207 | * 208 | * Copyright (C) 1989, 1991 Free Software Foundation, Inc., 209 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 210 | * Everyone is permitted to copy and distribute verbatim copies 211 | * of this license document, but changing it is not allowed. 212 | * 213 | * Preamble 214 | * 215 | * The licenses for most software are designed to take away your 216 | * freedom to share and change it. By contrast, the GNU General Public 217 | * License is intended to guarantee your freedom to share and change free 218 | * software--to make sure the software is free for all its users. This 219 | * General Public License applies to most of the Free Software 220 | * Foundation's software and to any other program whose authors commit to 221 | * using it. (Some other Free Software Foundation software is covered by 222 | * the GNU Lesser General Public License instead.) You can apply it to 223 | * your programs, too. 224 | * 225 | * When we speak of free software, we are referring to freedom, not 226 | * price. Our General Public Licenses are designed to make sure that you 227 | * have the freedom to distribute copies of free software (and charge for 228 | * this service if you wish), that you receive source code or can get it 229 | * if you want it, that you can change the software or use pieces of it 230 | * in new free programs; and that you know you can do these things. 231 | * 232 | * To protect your rights, we need to make restrictions that forbid 233 | * anyone to deny you these rights or to ask you to surrender the rights. 234 | * These restrictions translate to certain responsibilities for you if you 235 | * distribute copies of the software, or if you modify it. 236 | * 237 | * For example, if you distribute copies of such a program, whether 238 | * gratis or for a fee, you must give the recipients all the rights that 239 | * you have. You must make sure that they, too, receive or can get the 240 | * source code. And you must show them these terms so they know their 241 | * rights. 242 | * 243 | * We protect your rights with two steps: (1) copyright the software, and 244 | * (2) offer you this license which gives you legal permission to copy, 245 | * distribute and/or modify the software. 246 | * 247 | * Also, for each author's protection and ours, we want to make certain 248 | * that everyone understands that there is no warranty for this free 249 | * software. If the software is modified by someone else and passed on, we 250 | * want its recipients to know that what they have is not the original, so 251 | * that any problems introduced by others will not reflect on the original 252 | * authors' reputations. 253 | * 254 | * Finally, any free program is threatened constantly by software 255 | * patents. We wish to avoid the danger that redistributors of a free 256 | * program will individually obtain patent licenses, in effect making the 257 | * program proprietary. To prevent this, we have made it clear that any 258 | * patent must be licensed for everyone's free use or not licensed at all. 259 | * 260 | * The precise terms and conditions for copying, distribution and 261 | * modification follow. 262 | * 263 | * GNU GENERAL PUBLIC LICENSE 264 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 265 | * 266 | * 0. This License applies to any program or other work which contains 267 | * a notice placed by the copyright holder saying it may be distributed 268 | * under the terms of this General Public License. The "Program", below, 269 | * refers to any such program or work, and a "work based on the Program" 270 | * means either the Program or any derivative work under copyright law: 271 | * that is to say, a work containing the Program or a portion of it, 272 | * either verbatim or with modifications and/or translated into another 273 | * language. (Hereinafter, translation is included without limitation in 274 | * the term "modification".) Each licensee is addressed as "you". 275 | * 276 | * Activities other than copying, distribution and modification are not 277 | * covered by this License; they are outside its scope. The act of 278 | * running the Program is not restricted, and the output from the Program 279 | * is covered only if its contents constitute a work based on the 280 | * Program (independent of having been made by running the Program). 281 | * Whether that is true depends on what the Program does. 282 | * 283 | * 1. You may copy and distribute verbatim copies of the Program's 284 | * source code as you receive it, in any medium, provided that you 285 | * conspicuously and appropriately publish on each copy an appropriate 286 | * copyright notice and disclaimer of warranty; keep intact all the 287 | * notices that refer to this License and to the absence of any warranty; 288 | * and give any other recipients of the Program a copy of this License 289 | * along with the Program. 290 | * 291 | * You may charge a fee for the physical act of transferring a copy, and 292 | * you may at your option offer warranty protection in exchange for a fee. 293 | * 294 | * 2. You may modify your copy or copies of the Program or any portion 295 | * of it, thus forming a work based on the Program, and copy and 296 | * distribute such modifications or work under the terms of Section 1 297 | * above, provided that you also meet all of these conditions: 298 | * 299 | * a) You must cause the modified files to carry prominent notices 300 | * stating that you changed the files and the date of any change. 301 | * 302 | * b) You must cause any work that you distribute or publish, that in 303 | * whole or in part contains or is derived from the Program or any 304 | * part thereof, to be licensed as a whole at no charge to all third 305 | * parties under the terms of this License. 306 | * 307 | * c) If the modified program normally reads commands interactively 308 | * when run, you must cause it, when started running for such 309 | * interactive use in the most ordinary way, to print or display an 310 | * announcement including an appropriate copyright notice and a 311 | * notice that there is no warranty (or else, saying that you provide 312 | * a warranty) and that users may redistribute the program under 313 | * these conditions, and telling the user how to view a copy of this 314 | * License. (Exception: if the Program itself is interactive but 315 | * does not normally print such an announcement, your work based on 316 | * the Program is not required to print an announcement.) 317 | * 318 | * These requirements apply to the modified work as a whole. If 319 | * identifiable sections of that work are not derived from the Program, 320 | * and can be reasonably considered independent and separate works in 321 | * themselves, then this License, and its terms, do not apply to those 322 | * sections when you distribute them as separate works. But when you 323 | * distribute the same sections as part of a whole which is a work based 324 | * on the Program, the distribution of the whole must be on the terms of 325 | * this License, whose permissions for other licensees extend to the 326 | * entire whole, and thus to each and every part regardless of who wrote it. 327 | * 328 | * Thus, it is not the intent of this section to claim rights or contest 329 | * your rights to work written entirely by you; rather, the intent is to 330 | * exercise the right to control the distribution of derivative or 331 | * collective works based on the Program. 332 | * 333 | * In addition, mere aggregation of another work not based on the Program 334 | * with the Program (or with a work based on the Program) on a volume of 335 | * a storage or distribution medium does not bring the other work under 336 | * the scope of this License. 337 | * 338 | * 3. You may copy and distribute the Program (or a work based on it, 339 | * under Section 2) in object code or executable form under the terms of 340 | * Sections 1 and 2 above provided that you also do one of the following: 341 | * 342 | * a) Accompany it with the complete corresponding machine-readable 343 | * source code, which must be distributed under the terms of Sections 344 | * 1 and 2 above on a medium customarily used for software interchange; or, 345 | * 346 | * b) Accompany it with a written offer, valid for at least three 347 | * years, to give any third party, for a charge no more than your 348 | * cost of physically performing source distribution, a complete 349 | * machine-readable copy of the corresponding source code, to be 350 | * distributed under the terms of Sections 1 and 2 above on a medium 351 | * customarily used for software interchange; or, 352 | * 353 | * c) Accompany it with the information you received as to the offer 354 | * to distribute corresponding source code. (This alternative is 355 | * allowed only for noncommercial distribution and only if you 356 | * received the program in object code or executable form with such 357 | * an offer, in accord with Subsection b above.) 358 | * 359 | * The source code for a work means the preferred form of the work for 360 | * making modifications to it. For an executable work, complete source 361 | * code means all the source code for all modules it contains, plus any 362 | * associated interface definition files, plus the scripts used to 363 | * control compilation and installation of the executable. However, as a 364 | * special exception, the source code distributed need not include 365 | * anything that is normally distributed (in either source or binary 366 | * form) with the major components (compiler, kernel, and so on) of the 367 | * operating system on which the executable runs, unless that component 368 | * itself accompanies the executable. 369 | * 370 | * If distribution of executable or object code is made by offering 371 | * access to copy from a designated place, then offering equivalent 372 | * access to copy the source code from the same place counts as 373 | * distribution of the source code, even though third parties are not 374 | * compelled to copy the source along with the object code. 375 | * 376 | * 4. You may not copy, modify, sublicense, or distribute the Program 377 | * except as expressly provided under this License. Any attempt 378 | * otherwise to copy, modify, sublicense or distribute the Program is 379 | * void, and will automatically terminate your rights under this License. 380 | * However, parties who have received copies, or rights, from you under 381 | * this License will not have their licenses terminated so long as such 382 | * parties remain in full compliance. 383 | * 384 | * 5. You are not required to accept this License, since you have not 385 | * signed it. However, nothing else grants you permission to modify or 386 | * distribute the Program or its derivative works. These actions are 387 | * prohibited by law if you do not accept this License. Therefore, by 388 | * modifying or distributing the Program (or any work based on the 389 | * Program), you indicate your acceptance of this License to do so, and 390 | * all its terms and conditions for copying, distributing or modifying 391 | * the Program or works based on it. 392 | * 393 | * 6. Each time you redistribute the Program (or any work based on the 394 | * Program), the recipient automatically receives a license from the 395 | * original licensor to copy, distribute or modify the Program subject to 396 | * these terms and conditions. You may not impose any further 397 | * restrictions on the recipients' exercise of the rights granted herein. 398 | * You are not responsible for enforcing compliance by third parties to 399 | * this License. 400 | * 401 | * 7. If, as a consequence of a court judgment or allegation of patent 402 | * infringement or for any other reason (not limited to patent issues), 403 | * conditions are imposed on you (whether by court order, agreement or 404 | * otherwise) that contradict the conditions of this License, they do not 405 | * excuse you from the conditions of this License. If you cannot 406 | * distribute so as to satisfy simultaneously your obligations under this 407 | * License and any other pertinent obligations, then as a consequence you 408 | * may not distribute the Program at all. For example, if a patent 409 | * license would not permit royalty-free redistribution of the Program by 410 | * all those who receive copies directly or indirectly through you, then 411 | * the only way you could satisfy both it and this License would be to 412 | * refrain entirely from distribution of the Program. 413 | * 414 | * If any portion of this section is held invalid or unenforceable under 415 | * any particular circumstance, the balance of the section is intended to 416 | * apply and the section as a whole is intended to apply in other 417 | * circumstances. 418 | * 419 | * It is not the purpose of this section to induce you to infringe any 420 | * patents or other property right claims or to contest validity of any 421 | * such claims; this section has the sole purpose of protecting the 422 | * integrity of the free software distribution system, which is 423 | * implemented by public license practices. Many people have made 424 | * generous contributions to the wide range of software distributed 425 | * through that system in reliance on consistent application of that 426 | * system; it is up to the author/donor to decide if he or she is willing 427 | * to distribute software through any other system and a licensee cannot 428 | * impose that choice. 429 | * 430 | * This section is intended to make thoroughly clear what is believed to 431 | * be a consequence of the rest of this License. 432 | * 433 | * 8. If the distribution and/or use of the Program is restricted in 434 | * certain countries either by patents or by copyrighted interfaces, the 435 | * original copyright holder who places the Program under this License 436 | * may add an explicit geographical distribution limitation excluding 437 | * those countries, so that distribution is permitted only in or among 438 | * countries not thus excluded. In such case, this License incorporates 439 | * the limitation as if written in the body of this License. 440 | * 441 | * 9. The Free Software Foundation may publish revised and/or new versions 442 | * of the General Public License from time to time. Such new versions will 443 | * be similar in spirit to the present version, but may differ in detail to 444 | * address new problems or concerns. 445 | * 446 | * Each version is given a distinguishing version number. If the Program 447 | * specifies a version number of this License which applies to it and "any 448 | * later version", you have the option of following the terms and conditions 449 | * either of that version or of any later version published by the Free 450 | * Software Foundation. If the Program does not specify a version number of 451 | * this License, you may choose any version ever published by the Free Software 452 | * Foundation. 453 | * 454 | * 10. If you wish to incorporate parts of the Program into other free 455 | * programs whose distribution conditions are different, write to the author 456 | * to ask for permission. For software which is copyrighted by the Free 457 | * Software Foundation, write to the Free Software Foundation; we sometimes 458 | * make exceptions for this. Our decision will be guided by the two goals 459 | * of preserving the free status of all derivatives of our free software and 460 | * of promoting the sharing and reuse of software generally. 461 | * 462 | * NO WARRANTY 463 | * 464 | * 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 465 | * FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 466 | * OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 467 | * PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 468 | * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 469 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 470 | * TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 471 | * PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 472 | * REPAIR OR CORRECTION. 473 | * 474 | * 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 475 | * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 476 | * REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 477 | * INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 478 | * OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 479 | * TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 480 | * YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 481 | * PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 482 | * POSSIBILITY OF SUCH DAMAGES. 483 | * 484 | * END OF TERMS AND CONDITIONS 485 | * 486 | * How to Apply These Terms to Your New Programs 487 | * 488 | * If you develop a new program, and you want it to be of the greatest 489 | * possible use to the public, the best way to achieve this is to make it 490 | * free software which everyone can redistribute and change under these terms. 491 | * 492 | * To do so, attach the following notices to the program. It is safest 493 | * to attach them to the start of each source file to most effectively 494 | * convey the exclusion of warranty; and each file should have at least 495 | * the "copyright" line and a pointer to where the full notice is found. 496 | * 497 | * testgauss.c - statistical tests for gaussian random numbers 498 | * Copyright (C) 2005 Jochen Voss. 499 | * 500 | * This program is free software; you can redistribute it and/or modify 501 | * it under the terms of the GNU General Public License as published by 502 | * the Free Software Foundation; either version 2 of the License, or 503 | * (at your option) any later version. 504 | * 505 | * This program is distributed in the hope that it will be useful, 506 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 507 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 508 | * GNU General Public License for more details. 509 | * 510 | * You should have received a copy of the GNU General Public License along 511 | * with this program; if not, write to the Free Software Foundation, Inc., 512 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 513 | * 514 | * Also add information on how to contact you by electronic and paper mail. 515 | * 516 | * If the program is interactive, make it output a short notice like this 517 | * when it starts in an interactive mode: 518 | * 519 | * Gnomovision version 69, Copyright (C) year name of author 520 | * Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 521 | * This is free software, and you are welcome to redistribute it 522 | * under certain conditions; type `show c' for details. 523 | * 524 | * The hypothetical commands `show w' and `show c' should show the appropriate 525 | * parts of the General Public License. Of course, the commands you use may 526 | * be called something other than `show w' and `show c'; they could even be 527 | * mouse-clicks or menu items--whatever suits your program. 528 | * 529 | * You should also get your employer (if you work as a programmer) or your 530 | * school, if any, to sign a "copyright disclaimer" for the program, if 531 | * necessary. Here is a sample; alter the names: 532 | * 533 | * Yoyodyne, Inc., hereby disclaims all copyright interest in the program 534 | * `Gnomovision' (which makes passes at compilers) written by James Hacker. 535 | * 536 | * , 1 April 1989 537 | * Ty Coon, President of Vice 538 | * 539 | * This General Public License does not permit incorporating your program into 540 | * proprietary programs. If your program is a subroutine library, you may 541 | * consider it more useful to permit linking proprietary applications with the 542 | * library. If this is what you want to do, use the GNU Lesser General 543 | * Public License instead of this License. 544 | */ 545 | --------------------------------------------------------------------------------