brazzy / floating-point-gui.de

Website that provides concise answers to common questions about floating-point numbers.
http://floating-point-gui.de/
1.02k stars 167 forks source link

Potentialy erroneous test case? #80

Open ulfben opened 1 year ago

ulfben commented 1 year ago

Hi!

I'm currently porting your nearlyEqual-implementation and test cases to C++. Hoping to send you the results in a day or two.

However, one of the test cases fails and I'm wondering if it might in fact be an erroneous test case?

/** Comparisons of numbers on opposite sides of 0 */
    @Test
    public void opposite() {
        assertFalse(nearlyEqual(1.000000001f, -1.0f));
        assertFalse(nearlyEqual(-1.0f, 1.000000001f));
        assertFalse(nearlyEqual(-1.000000001f, 1.0f));
        assertFalse(nearlyEqual(1.0f, -1.000000001f));
        assertTrue(nearlyEqual(10 * Float.MIN_VALUE, 10 * -Float.MIN_VALUE)); //<-- inverted assert? 
        assertFalse(nearlyEqual(10000 * Float.MIN_VALUE, 10000 * -Float.MIN_VALUE));
    }

The second to last test; nearlyEqual(10 * MIN_VALUE, 10 * -MIN_VALUE) , evaluates to false for me. Is there something weird going on in my end, or should that test actually be assertFalse?

My Google Test case for reference:

TEST(NearlyEqual, opposite) {
    static constexpr auto MIN = std::numeric_limits<float>::min();
    EXPECT_FALSE(nearly_equal(1.000000001f, -1.0f));
    EXPECT_FALSE(nearly_equal(-1.0f, 1.000000001f));
    EXPECT_FALSE(nearly_equal(-1.000000001f, 1.0f));
    EXPECT_FALSE(nearly_equal(1.0f, -1.000000001f));
    EXPECT_TRUE(nearly_equal(10.0f * MIN, 10.0f * -MIN)); //this fails for me    
    EXPECT_FALSE(nearly_equal(10000.0f * MIN, 10000.0f * -MIN));
}

I am using the same epsilon (0.00001f) as you, and I'm not compiling with the fast floating point flag.

ulfben commented 1 year ago

There is probably something more going on. All the ulp tests fail as well. Am I missunderstanding what Java's Float.MIN_VALUE represents?

TEST(NearlyEqualTest, ulp) {
    static constexpr auto MIN = std::numeric_limits<float>::min();

    EXPECT_TRUE(nearly_equal(MIN, MIN)); //pass
    EXPECT_TRUE(nearly_equal(MIN, -MIN)); //fail
    EXPECT_TRUE(nearly_equal(-MIN, MIN)); //fail
    EXPECT_TRUE(nearly_equal(MIN, 0.0f)); //fail
    EXPECT_TRUE(nearly_equal(0.0f, MIN)); //fail
    EXPECT_TRUE(nearly_equal(-MIN, 0.0f)); //fail
    EXPECT_TRUE(nearly_equal(0.0f, -MIN)); //fail

    EXPECT_FALSE(nearly_equal(0.000000001f, -MIN)); //pass
    EXPECT_FALSE(nearly_equal(0.000000001f, MIN)); //pass
    EXPECT_FALSE(nearly_equal(MIN, 0.000000001f)); //pass
    EXPECT_FALSE(nearly_equal(-MIN, 0.000000001f)); //pass

    //sanity check:
    EXPECT_FLOAT_EQ(MIN, -MIN); //fail: 1.1754944e-38 != -1.1754944e-38
}