Skip to content

Instantly share code, notes, and snippets.

@brunokim
Created February 6, 2014 12:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brunokim/8843039 to your computer and use it in GitHub Desktop.
Save brunokim/8843039 to your computer and use it in GitHub Desktop.
Testing a chaotic function with different rounding modes for all float values.
// 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]);
}
}
}
@totalgee
Copy link

totalgee commented Feb 6, 2014

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment