Created
February 6, 2014 12:15
-
-
Save brunokim/8843039 to your computer and use it in GitHub Desktop.
Testing a chaotic function with different rounding modes for all float values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compiled with gcc -o sum_test -O0 --std=c99 sum_test.c -lm -Wall -Wextra | |
#include <assert.h> | |
#include <math.h> | |
#include <fenv.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
// Based on | |
// http://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ | |
typedef float (*Transform)(float); | |
typedef union Float_s { | |
int32_t i; | |
float f; | |
} Float_s; | |
void exhaustive_test(uint32_t start, uint32_t stop, Transform test, Transform ref, const char *desc) { | |
long long i = start; | |
while (i <= stop) { | |
Float_s input; | |
input.i = (int32_t) i; | |
Float_s test_value = (Float_s) test(input.f); | |
Float_s ref_value = (Float_s) ref(input.f); | |
// If the results dont match, and are not NaNs, report error | |
if (test_value.f != ref_value.f && | |
(test_value.f == test_value.f || ref_value.f == ref_value.f)) { | |
printf("%s %.9g %.9g %1.9g\n", desc, input.f, ref_value.f, test_value.f); | |
} | |
++i; | |
} | |
} | |
float round_to_0(float x) { | |
assert(!fesetround(0)); | |
x = sinf(2.3f*x) + cosf(3.7f*x); | |
return x; | |
} | |
float round_to_nearest(float x) { | |
assert(!fesetround(1)); | |
x = sinf(2.3f*x) + cosf(3.7f*x); | |
return x; | |
} | |
float round_to_pos_infty(float x) { | |
assert(!fesetround(2)); | |
x = sinf(2.3f*x) + cosf(3.7f*x); | |
return x; | |
} | |
float round_to_neg_infty(float x) { | |
assert(!fesetround(3)); | |
x = sinf(2.3f*x) + cosf(3.7f*x); | |
return x; | |
} | |
int main() { | |
Float_s max_float = (Float_s) 21477483520.0f; | |
const uint32_t sign_bit = 0x8000000; | |
Transform f[] = {round_to_0, round_to_nearest, round_to_pos_infty, round_to_neg_infty}; | |
const char *descs[] = {"to-zero ", | |
"to-nearest ", | |
"to-pos-infty", | |
"to-neg-infty"}; | |
bool is_round_mode_available[] = {!fesetround(0), !fesetround(1), !fesetround(2), !fesetround(3)}; | |
if (!is_round_mode_available[0]){ | |
fprintf(stderr, "Error: rounding mode %s not available!\n", descs[0]); | |
return 1; | |
} | |
for (int i=1; i < 4; i++) { | |
if (is_round_mode_available[i]){ | |
char desc[20]; | |
sprintf(desc, "pos-%s", descs[i]); | |
exhaustive_test(0, (uint32_t) max_float.i, f[i], f[0], desc); | |
sprintf(desc, "neg-%s", descs[i]); | |
exhaustive_test(sign_bit, sign_bit | max_float.i, f[i], f[0], desc); | |
} else { | |
fprintf(stderr, "Error: rounding mode %s not available\n", descs[i]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cool! But this won't work because you're hardcoding 0 through 3 as the arguments to fesetround(), rather than the proper #defined values:
(e.g. on my Mac, from fenv.h)
define FE_TONEAREST 0x0000
define FE_DOWNWARD 0x0400
define FE_UPWARD 0x0800
define FE_TOWARDZERO 0x0c00
You should use the defines (FE_DOWNWARD, etc).