diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index f3bd1fe833..1d25deaa55 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -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 diff --git a/vlib/builtin/float.v b/vlib/builtin/float.v index dbb2a961d1..1418aab8eb 100644 --- a/vlib/builtin/float.v +++ b/vlib/builtin/float.v @@ -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 + } } diff --git a/vlib/builtin/float_test.v b/vlib/builtin/float_test.v index 09503561fa..af30f711f1 100644 --- a/vlib/builtin/float_test.v +++ b/vlib/builtin/float_test.v @@ -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) +} diff --git a/vlib/builtin/int_test.v b/vlib/builtin/int_test.v index ac9454b640..0368dd65e1 100644 --- a/vlib/builtin/int_test.v +++ b/vlib/builtin/int_test.v @@ -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' diff --git a/vlib/math/complex/complex_test.v b/vlib/math/complex/complex_test.v index b74c66998e..65cac0e658 100644 --- a/vlib/math/complex/complex_test.v +++ b/vlib/math/complex/complex_test.v @@ -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 } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 33bcb69bb3..586f0239f1 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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 diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 15983d1c6e..e99860d538 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -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