2011-11-21 02:59:51 +08:00
|
|
|
#include <cstdlib>
|
2013-05-11 21:31:51 +08:00
|
|
|
#include <ctime>
|
2011-05-08 20:26:13 +08:00
|
|
|
#include <limits>
|
2013-05-11 21:31:51 +08:00
|
|
|
#include <cfloat>
|
2011-11-21 02:59:51 +08:00
|
|
|
#include <cmath>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cassert>
|
2011-05-08 20:26:13 +08:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define random() rand()
|
2011-05-11 18:50:56 +08:00
|
|
|
#define nextafterf(a, b) (throw "no nextafterf", 0);
|
2011-05-08 20:26:13 +08:00
|
|
|
#endif
|
|
|
|
|
2016-02-16 21:00:54 +08:00
|
|
|
#include <util/ieee_float.h>
|
2011-05-08 20:26:13 +08:00
|
|
|
|
|
|
|
#define PINF (std::numeric_limits<float>::infinity())
|
|
|
|
#define NINF (-std::numeric_limits<float>::infinity())
|
2011-06-13 22:58:28 +08:00
|
|
|
#ifndef NZERO
|
2011-05-08 20:26:13 +08:00
|
|
|
#define NZERO (-0.0f)
|
2011-06-13 22:58:28 +08:00
|
|
|
#endif
|
2011-05-08 20:26:13 +08:00
|
|
|
#define PZERO (0.0f)
|
|
|
|
|
|
|
|
#ifndef NAN
|
|
|
|
# define NAN (std::numeric_limits<float>::quiet_NaN())
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-11-01 03:36:41 +08:00
|
|
|
std::string float2binary(float f)
|
|
|
|
{
|
2016-11-28 23:41:24 +08:00
|
|
|
union
|
2011-11-01 03:36:41 +08:00
|
|
|
{
|
|
|
|
float f;
|
|
|
|
int i;
|
|
|
|
} c;
|
|
|
|
|
|
|
|
c.f = f;
|
2017-02-20 19:46:28 +08:00
|
|
|
return integer2binary(c.i, 32);
|
2011-11-01 03:36:41 +08:00
|
|
|
}
|
|
|
|
|
2011-05-08 20:26:13 +08:00
|
|
|
float random_float()
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
|
|
|
float f;
|
|
|
|
unsigned i;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
|
|
|
|
unsigned r = ((unsigned) random()) % 20;
|
|
|
|
|
|
|
|
switch(r)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return PINF;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
return NINF;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
return NAN;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
return PZERO;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
return NZERO;
|
|
|
|
break;
|
2016-11-28 23:41:24 +08:00
|
|
|
default:
|
2011-05-08 20:26:13 +08:00
|
|
|
u.i=random();
|
|
|
|
u.i=(u.i<<16)^random();
|
|
|
|
return u.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool eq(const ieee_floatt &a, const ieee_floatt &b)
|
|
|
|
{
|
|
|
|
if(a.is_NaN() && b.is_NaN()) return true;
|
|
|
|
if(a.is_infinity() && b.is_infinity() && a.get_sign()==b.get_sign()) return true;
|
|
|
|
return a==b;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum { PLUS=0, MINUS=1, MULT=2, DIV=3 } binopt;
|
|
|
|
typedef enum { EQ=0, NEQ=1, LT=2, LE=3, GT=4, GE=5} binrel;
|
|
|
|
const char *binopsyms[]={ " + ", " - ", " * ", " / " };
|
|
|
|
const char *binrelsyms[]={ " == ", " != ", " < ", " <= ", " > ", " >= "};
|
|
|
|
|
|
|
|
void check_arithmetic(int i)
|
|
|
|
{
|
|
|
|
ieee_floatt i1, i2, i3, res;
|
|
|
|
float f1, f2, f3;
|
|
|
|
|
|
|
|
f1=random_float();
|
|
|
|
f2=random_float();
|
|
|
|
i1.from_float(f1);
|
|
|
|
i2.from_float(f2);
|
|
|
|
res=i1;
|
|
|
|
f3=f1;
|
|
|
|
|
|
|
|
int op=(binopt)i%4;
|
|
|
|
|
|
|
|
switch(op)
|
|
|
|
{
|
|
|
|
case PLUS:
|
|
|
|
f3+=f2;
|
|
|
|
res+=i2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MINUS:
|
|
|
|
f3-=f2;
|
|
|
|
res-=i2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MULT:
|
|
|
|
f3*=f2;
|
|
|
|
res*=i2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DIV:
|
|
|
|
f3/=f2;
|
|
|
|
res/=i2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
i3.from_float(f3);
|
|
|
|
|
|
|
|
if(!eq(res, i3))
|
|
|
|
{
|
|
|
|
const char *opsym=binopsyms[op];
|
|
|
|
std::cout << i1 << opsym << i2 << " != " << res << std::endl;
|
|
|
|
std::cout << f1 << opsym << f2 << " == " << f3 << std::endl;
|
|
|
|
std::cout << integer2binary(i1.get_fraction(), i1.spec.f+1) << opsym <<
|
|
|
|
integer2binary(i2.get_fraction(), i1.spec.f+1) << " != " <<
|
|
|
|
integer2binary(res.get_fraction(), i1.spec.f+1) <<
|
|
|
|
" (" << res.get_fraction() << ")" << std::endl;
|
|
|
|
std::cout << integer2binary(i1.get_fraction(), i1.spec.f+1) << opsym <<
|
|
|
|
integer2binary(i2.get_fraction(), i1.spec.f+1) << " == " <<
|
|
|
|
integer2binary(i3.get_fraction(), i1.spec.f+1) <<
|
|
|
|
" (" << i3.get_fraction() << ")" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void check_comparison(int i)
|
|
|
|
{
|
|
|
|
ieee_floatt i1, i2;
|
|
|
|
float f1, f2;
|
|
|
|
|
|
|
|
bool ires, fres;
|
|
|
|
|
|
|
|
f1=random_float();
|
|
|
|
f2=random_float();
|
|
|
|
i1.from_float(f1);
|
|
|
|
i2.from_float(f2);
|
|
|
|
|
|
|
|
int op=(binrel)i%6;
|
2016-11-28 23:41:24 +08:00
|
|
|
|
|
|
|
switch(op)
|
2011-05-08 20:26:13 +08:00
|
|
|
{
|
|
|
|
case EQ:
|
2017-02-20 19:46:28 +08:00
|
|
|
ires = ieee_equal(i1, i2);
|
2011-05-08 20:26:13 +08:00
|
|
|
fres = (f1 == f2);
|
|
|
|
break;
|
|
|
|
case NEQ:
|
2017-02-20 19:46:28 +08:00
|
|
|
ires = ieee_not_equal(i1, i2);
|
2011-05-08 20:26:13 +08:00
|
|
|
fres = (f1 != f2);
|
|
|
|
break;
|
|
|
|
case LT:
|
|
|
|
ires = (i1 < i2);
|
|
|
|
fres = (f1 < f2);
|
|
|
|
break;
|
|
|
|
case LE:
|
|
|
|
ires = (i1 <= i2);
|
|
|
|
fres = (f1 <= f2);
|
|
|
|
break;
|
|
|
|
case GT:
|
|
|
|
ires = (i1 > i2);
|
|
|
|
fres = (f1 > f2);
|
|
|
|
break;
|
|
|
|
case GE:
|
|
|
|
ires = (i1 >= i2);
|
|
|
|
fres = (f1 >= f2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ires != fres)
|
|
|
|
{
|
|
|
|
const char *opsym=binrelsyms[op];
|
|
|
|
std::cout << i1 << opsym << i2 << " != " << ires << std::endl;
|
|
|
|
std::cout << f1 << opsym << f2 << " == " << fres << std::endl;
|
|
|
|
std::cout << integer2binary(i1.get_fraction(), i1.spec.f+1) << opsym <<
|
|
|
|
integer2binary(i2.get_fraction(), i1.spec.f+1) << " != " << ires;
|
|
|
|
std::cout << integer2binary(i1.get_fraction(), i1.spec.f+1) << opsym <<
|
|
|
|
integer2binary(i2.get_fraction(), i1.spec.f+1) << " == " << fres;
|
|
|
|
std::cout << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void check_conversion(int i)
|
|
|
|
{
|
2016-11-28 23:41:24 +08:00
|
|
|
union
|
|
|
|
{
|
2011-05-08 20:26:13 +08:00
|
|
|
float f;
|
|
|
|
unsigned i;
|
|
|
|
} a, b;
|
|
|
|
|
|
|
|
a.f = random_float();
|
|
|
|
|
|
|
|
ieee_floatt t;
|
|
|
|
t.from_float(a.f);
|
|
|
|
|
|
|
|
assert(t.is_float());
|
|
|
|
b.f = t.to_float();
|
|
|
|
|
|
|
|
if(a.i != b.i && !((a.f != a.f) && (b.f != b.f)))
|
|
|
|
{
|
2016-11-28 23:41:24 +08:00
|
|
|
std::cout << "conversion failure: " << a.f << " -> " << t << " -> "
|
2011-05-08 20:26:13 +08:00
|
|
|
<< b.f << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void check_nextafter(int i)
|
|
|
|
{
|
|
|
|
float f1 = random_float();
|
2011-05-11 18:50:27 +08:00
|
|
|
float f2 = nextafterf(f1, PINF);
|
|
|
|
float f3 = nextafterf(f1, NINF);
|
2016-11-28 23:41:24 +08:00
|
|
|
|
2011-05-08 20:26:13 +08:00
|
|
|
ieee_floatt i1, i2, i3;
|
2016-11-28 23:41:24 +08:00
|
|
|
|
2011-05-08 20:26:13 +08:00
|
|
|
i1.from_float(f1);
|
2011-11-01 03:36:41 +08:00
|
|
|
i2 = i1;
|
2011-11-12 15:15:24 +08:00
|
|
|
i2.increment(false);
|
2011-11-01 03:36:41 +08:00
|
|
|
i3 = i1;
|
2011-11-12 15:15:24 +08:00
|
|
|
i3.decrement(false);
|
2011-05-08 20:26:13 +08:00
|
|
|
|
|
|
|
if((f1 != i1.to_float() && !(f1 != f1 && i1.is_NaN())) ||
|
|
|
|
(f2 != i2.to_float() && !(f2 != f2 && i2.is_NaN())) ||
|
|
|
|
(f3 != i3.to_float() && !(f3 != f3 && i3.is_NaN())))
|
|
|
|
{
|
2016-11-28 23:41:24 +08:00
|
|
|
std::cout << "Incorrect nextafter: " << std::endl
|
2011-11-12 15:15:24 +08:00
|
|
|
<< "mach float: " << f1 << " " << f2 << " " << f3 << std::endl
|
2016-11-28 23:41:24 +08:00
|
|
|
<< "ieee_float: " << i1.to_float() << " "
|
2011-05-08 20:26:13 +08:00
|
|
|
<< i2.to_float() << " " << i3.to_float() << std::endl;
|
2016-11-28 23:41:24 +08:00
|
|
|
std::cout << "Binary representation: " << std::endl
|
|
|
|
<< "mach float: " << float2binary(f1) << " "
|
2011-11-01 03:36:41 +08:00
|
|
|
<< float2binary(f2) << " " << float2binary(f3) << std::endl
|
2016-11-28 23:41:24 +08:00
|
|
|
<< "ieee_float: " << float2binary(i1.to_float()) << " "
|
|
|
|
<< float2binary(i2.to_float())
|
2011-11-01 03:36:41 +08:00
|
|
|
<< " " << float2binary(i3.to_float()) << std::endl;
|
2016-11-28 23:41:24 +08:00
|
|
|
|
2011-05-08 20:26:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void check_minmax()
|
|
|
|
{
|
|
|
|
float f = 0;
|
|
|
|
ieee_floatt t;
|
|
|
|
t.from_float(f);
|
|
|
|
|
|
|
|
t.make_fltmax();
|
|
|
|
if(t.to_float() != FLT_MAX)
|
|
|
|
std::cout << "make_fltmax is broken" << std::endl;
|
|
|
|
|
|
|
|
t.make_fltmin();
|
|
|
|
if(t.to_float() != FLT_MIN)
|
|
|
|
std::cout << "make_fltmin is broken:"
|
2016-11-28 23:41:24 +08:00
|
|
|
<< std::endl << " machine float: " << FLT_MIN
|
|
|
|
<< ", ieee_floatt: " << t.to_float() << "("
|
2011-05-08 20:26:13 +08:00
|
|
|
<< (t.to_float() == FLT_MIN) << ")" << std::endl;
|
|
|
|
}
|
|
|
|
|
2011-11-12 15:15:24 +08:00
|
|
|
void check_build_extract()
|
|
|
|
{
|
|
|
|
float f = random_float();
|
|
|
|
ieee_floatt t;
|
|
|
|
t.from_float(f);
|
|
|
|
|
|
|
|
mp_integer old_frac, old_exp;
|
2013-10-09 23:58:05 +08:00
|
|
|
t.extract_base2(old_frac, old_exp);
|
2011-11-12 15:15:24 +08:00
|
|
|
mp_integer frac_bak=old_frac, exp_bak=old_exp;
|
|
|
|
t.build(old_frac, old_exp);
|
2013-10-09 23:58:05 +08:00
|
|
|
t.extract_base2(old_frac, old_exp);
|
2011-11-12 15:15:24 +08:00
|
|
|
if(frac_bak != old_frac || exp_bak != old_exp)
|
|
|
|
std::cout << "extract - build - extract is broken for " << t << std::endl;
|
|
|
|
}
|
|
|
|
|
2011-05-08 20:26:13 +08:00
|
|
|
int main()
|
|
|
|
{
|
|
|
|
srand(time(0));
|
|
|
|
check_minmax();
|
|
|
|
|
2016-02-16 21:00:54 +08:00
|
|
|
for(unsigned i=0; i<100000; i++)
|
2011-05-08 20:26:13 +08:00
|
|
|
{
|
2011-11-01 03:36:41 +08:00
|
|
|
if(i%10000==0) std::cout << "*********** " << i << std::endl;
|
2011-05-08 20:26:13 +08:00
|
|
|
check_arithmetic(i);
|
|
|
|
check_comparison(i);
|
|
|
|
check_conversion(i);
|
|
|
|
check_nextafter(i);
|
2011-11-12 15:15:24 +08:00
|
|
|
check_build_extract();
|
2011-05-08 20:26:13 +08:00
|
|
|
}
|
|
|
|
}
|