cgen: use standard checks for float comparisons
parent
42e314d281
commit
cf9498ef6b
|
@ -174,27 +174,6 @@ fn C.WIFSIGNALED() bool
|
|||
fn C.WTERMSIG() int
|
||||
|
||||
|
||||
fn C.DEFAULT_LE() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_EQ() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_GT() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_EQUAL() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_NOT_EQUAL() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_LT() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_GE() bool
|
||||
|
||||
|
||||
fn C.isatty() int
|
||||
|
||||
|
||||
|
|
|
@ -86,107 +86,61 @@ fn f64_abs(a f64) f64 {
|
|||
}
|
||||
}
|
||||
|
||||
// compare floats using C epsilon
|
||||
// ==
|
||||
|
||||
[inline]
|
||||
pub fn (a f64) eq(b f64) bool {
|
||||
return f64_abs(a - b) <= C.DBL_EPSILON
|
||||
fn f32_max(a, b f32) f32 {
|
||||
return if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (a f32) eq(b f32) bool {
|
||||
return f32_abs(a - b) <= f32(C.FLT_EPSILON)
|
||||
fn f32_min(a, b f32) f32 {
|
||||
return if a < b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (a f64) eqbit(b f64) bool {
|
||||
return C.DEFAULT_EQUAL(a, b)
|
||||
[inline]
|
||||
fn f64_max(a, b f64) f64 {
|
||||
return if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (a f32) eqbit(b f32) bool {
|
||||
return C.DEFAULT_EQUAL(a, b)
|
||||
[inline]
|
||||
fn f64_min(a, b f64) f64 {
|
||||
return if a < b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
// !=
|
||||
fn (a f64) ne(b f64) bool {
|
||||
return !a.eq(b)
|
||||
[inline]
|
||||
fn (a f32) eq_epsilon(b f32) bool {
|
||||
hi := f32_max(f32_abs(a), f32_abs(b))
|
||||
delta := f32_abs(a - b)
|
||||
if hi > f32(1.0) {
|
||||
return delta <= hi * (4 * f32(C.FLT_EPSILON))
|
||||
} else {
|
||||
return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi
|
||||
}
|
||||
}
|
||||
|
||||
fn (a f32) ne(b f32) bool {
|
||||
return !a.eq(b)
|
||||
}
|
||||
|
||||
pub fn (a f64) nebit(b f64) bool {
|
||||
return C.DEFAULT_NOT_EQUAL(a, b)
|
||||
}
|
||||
|
||||
pub fn (a f32) nebit(b f32) bool {
|
||||
return C.DEFAULT_NOT_EQUAL(a, b)
|
||||
}
|
||||
|
||||
// a < b
|
||||
fn (a f64) lt(b f64) bool {
|
||||
return a.ne(b) && a.ltbit(b)
|
||||
}
|
||||
|
||||
fn (a f32) lt(b f32) bool {
|
||||
return a.ne(b) && a.ltbit(b)
|
||||
}
|
||||
|
||||
fn (a f64) ltbit(b f64) bool {
|
||||
return C.DEFAULT_LT(a, b)
|
||||
}
|
||||
|
||||
fn (a f32) ltbit(b f32) bool {
|
||||
return C.DEFAULT_LT(a, b)
|
||||
}
|
||||
|
||||
// a <= b
|
||||
fn (a f64) le(b f64) bool {
|
||||
return !a.gt(b)
|
||||
}
|
||||
|
||||
fn (a f32) le(b f32) bool {
|
||||
return !a.gt(b)
|
||||
}
|
||||
|
||||
fn (a f64) lebit(b f64) bool {
|
||||
return C.DEFAULT_LE(a, b)
|
||||
}
|
||||
|
||||
fn (a f32) lebit(b f32) bool {
|
||||
return C.DEFAULT_LE(a, b)
|
||||
}
|
||||
|
||||
// a > b
|
||||
fn (a f64) gt(b f64) bool {
|
||||
return a.ne(b) && a.gtbit(b)
|
||||
}
|
||||
|
||||
fn (a f32) gt(b f32) bool {
|
||||
return a.ne(b) && a.gtbit(b)
|
||||
}
|
||||
|
||||
fn (a f64) gtbit(b f64) bool {
|
||||
return C.DEFAULT_GT(a, b)
|
||||
}
|
||||
|
||||
fn (a f32) gtbit(b f32) bool {
|
||||
return C.DEFAULT_GT(a, b)
|
||||
}
|
||||
|
||||
// a >= b
|
||||
fn (a f64) ge(b f64) bool {
|
||||
return !a.lt(b)
|
||||
}
|
||||
|
||||
fn (a f32) ge(b f32) bool {
|
||||
return !a.lt(b)
|
||||
}
|
||||
|
||||
fn (a f64) gebit(b f64) bool {
|
||||
return C.DEFAULT_GE(a, b)
|
||||
}
|
||||
|
||||
fn (a f32) gebit(b f32) bool {
|
||||
return C.DEFAULT_GE(a, b)
|
||||
[inline]
|
||||
fn (a f64) eq_epsilon(b f64) bool {
|
||||
hi := f64_max(f64_abs(a), f64_abs(b))
|
||||
delta := f64_abs(a - b)
|
||||
if hi > 1.0 {
|
||||
return delta <= hi * (4 * f64(C.DBL_EPSILON))
|
||||
} else {
|
||||
return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,3 +34,114 @@ fn test_float_decl() {
|
|||
assert typeof(x15) == 'f64'
|
||||
assert typeof(x16) == 'f64'
|
||||
}
|
||||
|
||||
fn test_f32_equal_operator() {
|
||||
b := f32(1.0)
|
||||
mut a := f32(1.0)
|
||||
a += 0.0000019073486328125
|
||||
assert a != b
|
||||
a -= 0.0000019073486328125
|
||||
assert a == b
|
||||
assert -1 == 1 * -1
|
||||
assert -1.0 == 1.0 * -1.0
|
||||
a = 1
|
||||
a += 0.0000019073486328125
|
||||
a -= 0.0000019073486328125
|
||||
assert a == f32(1.0)
|
||||
a += 0.000001
|
||||
assert !(a < f32(1))
|
||||
assert !(a <= f32(1))
|
||||
assert a > f32(1)
|
||||
assert a >= 1
|
||||
assert a != 1
|
||||
f := 1.2
|
||||
ab := int(f)
|
||||
assert ab == 1
|
||||
e := f32(-1.602176634e-19)
|
||||
m := f32(9.1093837015e-31)
|
||||
assert e < m
|
||||
assert e <= m
|
||||
assert e != m
|
||||
assert !(e == m)
|
||||
assert m >= e
|
||||
assert m > e
|
||||
}
|
||||
|
||||
fn test_f64_equal_operator() {
|
||||
b := 1.0
|
||||
mut a := 1.0
|
||||
a += 0.0000019073486328125
|
||||
assert a != b
|
||||
a -= 0.0000019073486328125
|
||||
assert a == b
|
||||
e := -1.602176634e-19
|
||||
m := 9.1093837015e-31
|
||||
assert e < m
|
||||
assert e <= m
|
||||
assert e != m
|
||||
assert !(e == m)
|
||||
assert m >= e
|
||||
assert m > e
|
||||
}
|
||||
|
||||
fn test_f64_eq_epsilon() {
|
||||
a := 1.662248544459347e308
|
||||
b := 1.662248544459348e308
|
||||
x := 1.662248544459352e308
|
||||
assert a != b
|
||||
assert a.eq_epsilon(b)
|
||||
assert b.eq_epsilon(a)
|
||||
assert (-a).eq_epsilon(-b)
|
||||
assert (-b).eq_epsilon(-a)
|
||||
assert !a.eq_epsilon(x)
|
||||
assert !x.eq_epsilon(a)
|
||||
assert !a.eq_epsilon(-b)
|
||||
assert !(-a).eq_epsilon(b)
|
||||
c := 1.5367748374385438503
|
||||
d := -1.5367748374385447257
|
||||
z := 1.5367748378943546
|
||||
assert c != -d
|
||||
assert c.eq_epsilon(-d)
|
||||
assert d.eq_epsilon(-c)
|
||||
assert !c.eq_epsilon(z)
|
||||
assert !z.eq_epsilon(c)
|
||||
e := 2.531434251587394233e-308
|
||||
f := 2.531434251587395675e-308
|
||||
y := 2.531434251587398934e-308
|
||||
assert e != f
|
||||
assert e.eq_epsilon(f)
|
||||
assert (-f).eq_epsilon(-e)
|
||||
assert !e.eq_epsilon(y)
|
||||
assert !(-y).eq_epsilon(-e)
|
||||
}
|
||||
|
||||
fn test_f32_eq_epsilon() {
|
||||
a := f32(3.244331e38)
|
||||
b := f32(3.244332e38)
|
||||
x := f32(3.244338e38)
|
||||
assert a != b
|
||||
assert a.eq_epsilon(b)
|
||||
assert b.eq_epsilon(a)
|
||||
assert (-a).eq_epsilon(-b)
|
||||
assert (-b).eq_epsilon(-a)
|
||||
assert !a.eq_epsilon(x)
|
||||
assert !(-x).eq_epsilon(-a)
|
||||
assert !a.eq_epsilon(-b)
|
||||
assert !(-a).eq_epsilon(b)
|
||||
c := f32(0.9546742)
|
||||
d := f32(-0.9546745)
|
||||
z := f32(0.9546754)
|
||||
assert c != -d
|
||||
assert c.eq_epsilon(-d)
|
||||
assert d.eq_epsilon(-c)
|
||||
assert !c.eq_epsilon(z)
|
||||
assert !z.eq_epsilon(c)
|
||||
e := f32(-1.5004390e-38)
|
||||
f := f32(-1.5004395e-38)
|
||||
y := f32(-1.5004409e-38)
|
||||
assert e != f
|
||||
assert e.eq_epsilon(f)
|
||||
assert (-f).eq_epsilon(-e)
|
||||
assert !e.eq_epsilon(y)
|
||||
assert !(-y).eq_epsilon(-e)
|
||||
}
|
||||
|
|
|
@ -11,46 +11,6 @@ fn test_const() {
|
|||
assert u == 1 // make sure this works without the cast
|
||||
}
|
||||
|
||||
fn test_float_equal_operator() {
|
||||
b := f32(1.0)
|
||||
mut a := f32(1.0)
|
||||
a += 0.000001
|
||||
a -= 0.000001
|
||||
assert a == b
|
||||
assert !a.eqbit(1.0)
|
||||
assert !(a != f32(1.0))
|
||||
assert a.nebit(f32(1.0))
|
||||
a += 0.000001
|
||||
assert !(a < 1.0)
|
||||
assert !a.ltbit(1.0)
|
||||
assert !(a <= 1)
|
||||
assert !a.lebit(1)
|
||||
assert a > 1
|
||||
assert a.gtbit(1)
|
||||
assert a >= 1
|
||||
assert a.gebit(1)
|
||||
assert -1 == 1 * -1
|
||||
assert -1.0 == 1.0 * -1.0
|
||||
a = 1
|
||||
a += 0.000001
|
||||
a -= 0.000001
|
||||
assert a == f32(1.0)
|
||||
assert !a.eqbit(f32(1.0))
|
||||
assert !(a != f32(1.0))
|
||||
a += 0.000001
|
||||
assert !(a < f32(1))
|
||||
assert !a.ltbit(f32(1))
|
||||
assert !(a <= f32(1))
|
||||
assert !a.lebit(f32(1))
|
||||
assert a > f32(1)
|
||||
assert a.gtbit(f32(1))
|
||||
assert a >= 1
|
||||
assert a.gebit(1)
|
||||
f := 1.2
|
||||
ab := int(f)
|
||||
assert ab == 1
|
||||
}
|
||||
|
||||
fn test_str_methods() {
|
||||
assert i8(1).str() == '1'
|
||||
assert i8(-1).str() == '-1'
|
||||
|
|
|
@ -122,8 +122,8 @@ fn test_complex_abs() {
|
|||
mut c1 := cmplx.complex(3,4)
|
||||
assert c1.abs() == 5
|
||||
c1 = cmplx.complex(1,2)
|
||||
assert c1.abs().eq(math.sqrt(5))
|
||||
assert c1.abs().eq(c1.conjugate().abs())
|
||||
assert c1.abs() == math.sqrt(5)
|
||||
assert c1.abs() == c1.conjugate().abs()
|
||||
c1 = cmplx.complex(7,0)
|
||||
assert c1.abs() == 7
|
||||
}
|
||||
|
@ -132,17 +132,17 @@ fn test_complex_angle(){
|
|||
// Test is based on and verified from practice examples of Khan Academy
|
||||
// https://www.khanacademy.org/math/precalculus/imaginary-and-complex-numbers
|
||||
mut c := cmplx.complex(1, 0)
|
||||
assert (c.angle() * 180 / math.pi).eq(0)
|
||||
assert c.angle() * 180 / math.pi == 0
|
||||
c = cmplx.complex(1, 1)
|
||||
assert (c.angle() * 180 / math.pi).eq(45)
|
||||
assert c.angle() * 180 / math.pi == 45
|
||||
c = cmplx.complex(0, 1)
|
||||
assert (c.angle() * 180 / math.pi).eq(90)
|
||||
assert c.angle() * 180 / math.pi == 90
|
||||
c = cmplx.complex(-1, 1)
|
||||
assert (c.angle() * 180 / math.pi).eq(135)
|
||||
assert c.angle() * 180 / math.pi == 135
|
||||
c = cmplx.complex(-1, -1)
|
||||
assert (c.angle() * 180 / math.pi).eq(-135)
|
||||
assert c.angle() * 180 / math.pi == -135
|
||||
cc := c.conjugate()
|
||||
assert (cc.angle() + c.angle()).eq(0)
|
||||
assert cc.angle() + c.angle() == 0
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1899,25 +1899,6 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
}
|
||||
g.write(' }))')
|
||||
}
|
||||
} else if (left_type == node.right_type) && left_type.is_float() && node.op in [.eq, .ne] {
|
||||
// floats should be compared with epsilon
|
||||
if left_type == table.f64_type_idx {
|
||||
if node.op == .eq {
|
||||
g.write('f64_eq(')
|
||||
} else {
|
||||
g.write('f64_ne(')
|
||||
}
|
||||
} else {
|
||||
if node.op == .eq {
|
||||
g.write('f32_eq(')
|
||||
} else {
|
||||
g.write('f32_ne(')
|
||||
}
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(',')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else {
|
||||
a := left_sym.name[0].is_capital() || left_sym.name.contains('.')
|
||||
b := left_sym.kind != .alias
|
||||
|
|
|
@ -210,30 +210,6 @@ void* g_live_info = NULL;
|
|||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
||||
#define _IN(typ, val, arr) array_##typ##_contains(arr, val)
|
||||
#define _IN_MAP(val, m) map_exists(m, val)
|
||||
#define DEFAULT_EQUAL(a, b) (a == b)
|
||||
#define DEFAULT_NOT_EQUAL(a, b) (a != b)
|
||||
#define DEFAULT_LT(a, b) (a < b)
|
||||
#define DEFAULT_LE(a, b) (a <= b)
|
||||
#define DEFAULT_GT(a, b) (a > b)
|
||||
#define DEFAULT_GE(a, b) (a >= b)
|
||||
|
||||
// NB: macro_fXX_eq and macro_fXX_ne are NOT used
|
||||
// in the generated C code. They are here just for
|
||||
// completeness/testing.
|
||||
|
||||
#define macro_f64_eq(a, b) (a == b)
|
||||
#define macro_f64_ne(a, b) (a != b)
|
||||
#define macro_f64_lt(a, b) (a < b)
|
||||
#define macro_f64_le(a, b) (a <= b)
|
||||
#define macro_f64_gt(a, b) (a > b)
|
||||
#define macro_f64_ge(a, b) (a >= b)
|
||||
|
||||
#define macro_f32_eq(a, b) (a == b)
|
||||
#define macro_f32_ne(a, b) (a != b)
|
||||
#define macro_f32_lt(a, b) (a < b)
|
||||
#define macro_f32_le(a, b) (a <= b)
|
||||
#define macro_f32_gt(a, b) (a > b)
|
||||
#define macro_f32_ge(a, b) (a >= b)
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#undef PRId64
|
||||
|
|
Loading…
Reference in New Issue