oh no not again - comparing two bowls of petunias - sorry - floats, for equality












1
















Due to rounding errors, most floating-point numbers end up being
slightly imprecise.




https://www.floating-point-gui.de/errors/comparison/



public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / Math.min((absA + absB), Float.MAX_VALUE) < epsilon;
}
}


What is the universal standard value for epsilon, if, for instance, I wanted to hardcode it for an API that anyone could use for comparing any values?










share|improve this question


















  • 3





    Why not letting the users of your API decide what Epsilon they need?

    – maio290
    Nov 23 '18 at 15:14











  • Sure, I could do that, but the difference is meant to be relative thus universal?

    – Adam
    Nov 23 '18 at 15:34













  • I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

    – Adam
    Nov 26 '18 at 17:42
















1
















Due to rounding errors, most floating-point numbers end up being
slightly imprecise.




https://www.floating-point-gui.de/errors/comparison/



public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / Math.min((absA + absB), Float.MAX_VALUE) < epsilon;
}
}


What is the universal standard value for epsilon, if, for instance, I wanted to hardcode it for an API that anyone could use for comparing any values?










share|improve this question


















  • 3





    Why not letting the users of your API decide what Epsilon they need?

    – maio290
    Nov 23 '18 at 15:14











  • Sure, I could do that, but the difference is meant to be relative thus universal?

    – Adam
    Nov 23 '18 at 15:34













  • I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

    – Adam
    Nov 26 '18 at 17:42














1












1








1









Due to rounding errors, most floating-point numbers end up being
slightly imprecise.




https://www.floating-point-gui.de/errors/comparison/



public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / Math.min((absA + absB), Float.MAX_VALUE) < epsilon;
}
}


What is the universal standard value for epsilon, if, for instance, I wanted to hardcode it for an API that anyone could use for comparing any values?










share|improve this question















Due to rounding errors, most floating-point numbers end up being
slightly imprecise.




https://www.floating-point-gui.de/errors/comparison/



public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / Math.min((absA + absB), Float.MAX_VALUE) < epsilon;
}
}


What is the universal standard value for epsilon, if, for instance, I wanted to hardcode it for an API that anyone could use for comparing any values?







java






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 15:12









AdamAdam

2,28512252




2,28512252








  • 3





    Why not letting the users of your API decide what Epsilon they need?

    – maio290
    Nov 23 '18 at 15:14











  • Sure, I could do that, but the difference is meant to be relative thus universal?

    – Adam
    Nov 23 '18 at 15:34













  • I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

    – Adam
    Nov 26 '18 at 17:42














  • 3





    Why not letting the users of your API decide what Epsilon they need?

    – maio290
    Nov 23 '18 at 15:14











  • Sure, I could do that, but the difference is meant to be relative thus universal?

    – Adam
    Nov 23 '18 at 15:34













  • I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

    – Adam
    Nov 26 '18 at 17:42








3




3





Why not letting the users of your API decide what Epsilon they need?

– maio290
Nov 23 '18 at 15:14





Why not letting the users of your API decide what Epsilon they need?

– maio290
Nov 23 '18 at 15:14













Sure, I could do that, but the difference is meant to be relative thus universal?

– Adam
Nov 23 '18 at 15:34







Sure, I could do that, but the difference is meant to be relative thus universal?

– Adam
Nov 23 '18 at 15:34















I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

– Adam
Nov 26 '18 at 17:42





I was hoping for an answer elaborating on the values of Float.MIN_NORMAL and Float.MIN_VALUE.

– Adam
Nov 26 '18 at 17:42












2 Answers
2






active

oldest

votes


















1














There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:




  • the absolute value of those numbers

  • the kind of quantity they represent


For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.



Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.






share|improve this answer
























  • You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

    – Adam
    Nov 26 '18 at 17:42











  • If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

    – Milo Bem
    Nov 27 '18 at 9:29











  • I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

    – Adam
    Nov 27 '18 at 15:15



















0














public static boolean nearlyEqual(double a, double b) {
if (a == b) {
return true;
} else if (a == 0 || b == 0) {
return false;
} else {
BigDecimal diff = new BigDecimal("" + a)
.subtract(new BigDecimal("" + b))
.abs();
int exponentA = new Double(Math.log10(Math.abs(a))).intValue();
int exponentB = new Double(Math.log10(Math.abs(b))).intValue();
int sigFigsA = getSignificantFigs(a);
int sigFigsB = getSignificantFigs(b);
BigDecimal epsilon = new BigDecimal("0.1")
.scaleByPowerOfTen(Math.min(exponentA, exponentB))
.scaleByPowerOfTen(-1 * Math.max(sigFigsA, sigFigsB));
return diff.compareTo(epsilon) < 0;
}
}

public static int getSignificantFigs(double inputDouble) {
// remove any exponent
BigDecimal input = new BigDecimal("" + Math.abs(inputDouble))
.stripTrailingZeros();
if (input.scale() < 0) {
int exponent = new Double(
Math.log10(Math.abs(inputDouble)))
.intValue();
input = input.scaleByPowerOfTen(-1 * exponent);
}
return input.precision();
}


And some tests:



@Test
public void testDoubleComparisonOnePositiveOneNegative() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.234E300D,
-1.234E300D
), "because one's positive and one's negative");
}

@Test
public void testDoubleComparisonZeroes() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
0D,
0.0D
), "zeroes");
}

@Test
public void testDoubleComparisonBasicDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
2.3450D,
2345.0D
), "typical numbers");
}

@Test
public void testDoubleComparisonMassivelyDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E-300D
), "big number vs tiny number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers2() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.2345678901234E300D,
1.2345678901233E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers3() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE
), "big number equals");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE * 0.1
), "big number");
}

@Test
public void testDoubleComparisonHugeNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
-1.2345678901234E300D,
-1.2345678901233E300D
), "big negative numbers");
}

@Test
public void testDoubleComparisonTinyPositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012345E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012344E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyTinyNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.5E-322D,
1.4E-322D
), "tiny tiny number");
}

@Test
public void testDoubleComparisonTinyTinyTinyNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL
), "tiny tiny number");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL * 0.1
), "tiny tiny numbers not same");
}

@Test
public void testDoubleComparisonThirds() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.3333333333333333333333333333333333333333D,
1.3333333333333333333333333333333333333333D
), "thirds");
}





share|improve this answer
























  • I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

    – Milo Bem
    Nov 27 '18 at 17:31











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449095%2foh-no-not-again-comparing-two-bowls-of-petunias-sorry-floats-for-equality%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:




  • the absolute value of those numbers

  • the kind of quantity they represent


For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.



Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.






share|improve this answer
























  • You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

    – Adam
    Nov 26 '18 at 17:42











  • If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

    – Milo Bem
    Nov 27 '18 at 9:29











  • I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

    – Adam
    Nov 27 '18 at 15:15
















1














There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:




  • the absolute value of those numbers

  • the kind of quantity they represent


For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.



Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.






share|improve this answer
























  • You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

    – Adam
    Nov 26 '18 at 17:42











  • If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

    – Milo Bem
    Nov 27 '18 at 9:29











  • I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

    – Adam
    Nov 27 '18 at 15:15














1












1








1







There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:




  • the absolute value of those numbers

  • the kind of quantity they represent


For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.



Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.






share|improve this answer













There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:




  • the absolute value of those numbers

  • the kind of quantity they represent


For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.



Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 23 '18 at 15:22









Milo BemMilo Bem

822418




822418













  • You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

    – Adam
    Nov 26 '18 at 17:42











  • If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

    – Milo Bem
    Nov 27 '18 at 9:29











  • I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

    – Adam
    Nov 27 '18 at 15:15



















  • You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

    – Adam
    Nov 26 '18 at 17:42











  • If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

    – Milo Bem
    Nov 27 '18 at 9:29











  • I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

    – Adam
    Nov 27 '18 at 15:15

















You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

– Adam
Nov 26 '18 at 17:42





You are completely ignoring the relative difference calculated. Regardless of the massive size or the minute size of the inputs, the relative difference is dependent on the number of significant figures. For astronomers or particle physicists.

– Adam
Nov 26 '18 at 17:42













If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

– Milo Bem
Nov 27 '18 at 9:29





If you already understand that the relative difference is dependent on the number of significant figures how can you expect a universal epsilon? This is what i tried to explain in my answer - there isn't one epsilon because it depends on the values you compare and the domain. Not all comparisons are between numbers with defined significant figures either, unless you want to limits your library's usage to specific scientific applications.

– Milo Bem
Nov 27 '18 at 9:29













I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

– Adam
Nov 27 '18 at 15:15





I've come up with a method to calculate a suitable epsilon, as opposed to trying to find 'one size fits all'.

– Adam
Nov 27 '18 at 15:15













0














public static boolean nearlyEqual(double a, double b) {
if (a == b) {
return true;
} else if (a == 0 || b == 0) {
return false;
} else {
BigDecimal diff = new BigDecimal("" + a)
.subtract(new BigDecimal("" + b))
.abs();
int exponentA = new Double(Math.log10(Math.abs(a))).intValue();
int exponentB = new Double(Math.log10(Math.abs(b))).intValue();
int sigFigsA = getSignificantFigs(a);
int sigFigsB = getSignificantFigs(b);
BigDecimal epsilon = new BigDecimal("0.1")
.scaleByPowerOfTen(Math.min(exponentA, exponentB))
.scaleByPowerOfTen(-1 * Math.max(sigFigsA, sigFigsB));
return diff.compareTo(epsilon) < 0;
}
}

public static int getSignificantFigs(double inputDouble) {
// remove any exponent
BigDecimal input = new BigDecimal("" + Math.abs(inputDouble))
.stripTrailingZeros();
if (input.scale() < 0) {
int exponent = new Double(
Math.log10(Math.abs(inputDouble)))
.intValue();
input = input.scaleByPowerOfTen(-1 * exponent);
}
return input.precision();
}


And some tests:



@Test
public void testDoubleComparisonOnePositiveOneNegative() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.234E300D,
-1.234E300D
), "because one's positive and one's negative");
}

@Test
public void testDoubleComparisonZeroes() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
0D,
0.0D
), "zeroes");
}

@Test
public void testDoubleComparisonBasicDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
2.3450D,
2345.0D
), "typical numbers");
}

@Test
public void testDoubleComparisonMassivelyDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E-300D
), "big number vs tiny number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers2() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.2345678901234E300D,
1.2345678901233E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers3() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE
), "big number equals");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE * 0.1
), "big number");
}

@Test
public void testDoubleComparisonHugeNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
-1.2345678901234E300D,
-1.2345678901233E300D
), "big negative numbers");
}

@Test
public void testDoubleComparisonTinyPositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012345E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012344E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyTinyNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.5E-322D,
1.4E-322D
), "tiny tiny number");
}

@Test
public void testDoubleComparisonTinyTinyTinyNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL
), "tiny tiny number");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL * 0.1
), "tiny tiny numbers not same");
}

@Test
public void testDoubleComparisonThirds() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.3333333333333333333333333333333333333333D,
1.3333333333333333333333333333333333333333D
), "thirds");
}





share|improve this answer
























  • I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

    – Milo Bem
    Nov 27 '18 at 17:31
















0














public static boolean nearlyEqual(double a, double b) {
if (a == b) {
return true;
} else if (a == 0 || b == 0) {
return false;
} else {
BigDecimal diff = new BigDecimal("" + a)
.subtract(new BigDecimal("" + b))
.abs();
int exponentA = new Double(Math.log10(Math.abs(a))).intValue();
int exponentB = new Double(Math.log10(Math.abs(b))).intValue();
int sigFigsA = getSignificantFigs(a);
int sigFigsB = getSignificantFigs(b);
BigDecimal epsilon = new BigDecimal("0.1")
.scaleByPowerOfTen(Math.min(exponentA, exponentB))
.scaleByPowerOfTen(-1 * Math.max(sigFigsA, sigFigsB));
return diff.compareTo(epsilon) < 0;
}
}

public static int getSignificantFigs(double inputDouble) {
// remove any exponent
BigDecimal input = new BigDecimal("" + Math.abs(inputDouble))
.stripTrailingZeros();
if (input.scale() < 0) {
int exponent = new Double(
Math.log10(Math.abs(inputDouble)))
.intValue();
input = input.scaleByPowerOfTen(-1 * exponent);
}
return input.precision();
}


And some tests:



@Test
public void testDoubleComparisonOnePositiveOneNegative() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.234E300D,
-1.234E300D
), "because one's positive and one's negative");
}

@Test
public void testDoubleComparisonZeroes() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
0D,
0.0D
), "zeroes");
}

@Test
public void testDoubleComparisonBasicDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
2.3450D,
2345.0D
), "typical numbers");
}

@Test
public void testDoubleComparisonMassivelyDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E-300D
), "big number vs tiny number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers2() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.2345678901234E300D,
1.2345678901233E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers3() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE
), "big number equals");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE * 0.1
), "big number");
}

@Test
public void testDoubleComparisonHugeNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
-1.2345678901234E300D,
-1.2345678901233E300D
), "big negative numbers");
}

@Test
public void testDoubleComparisonTinyPositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012345E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012344E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyTinyNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.5E-322D,
1.4E-322D
), "tiny tiny number");
}

@Test
public void testDoubleComparisonTinyTinyTinyNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL
), "tiny tiny number");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL * 0.1
), "tiny tiny numbers not same");
}

@Test
public void testDoubleComparisonThirds() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.3333333333333333333333333333333333333333D,
1.3333333333333333333333333333333333333333D
), "thirds");
}





share|improve this answer
























  • I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

    – Milo Bem
    Nov 27 '18 at 17:31














0












0








0







public static boolean nearlyEqual(double a, double b) {
if (a == b) {
return true;
} else if (a == 0 || b == 0) {
return false;
} else {
BigDecimal diff = new BigDecimal("" + a)
.subtract(new BigDecimal("" + b))
.abs();
int exponentA = new Double(Math.log10(Math.abs(a))).intValue();
int exponentB = new Double(Math.log10(Math.abs(b))).intValue();
int sigFigsA = getSignificantFigs(a);
int sigFigsB = getSignificantFigs(b);
BigDecimal epsilon = new BigDecimal("0.1")
.scaleByPowerOfTen(Math.min(exponentA, exponentB))
.scaleByPowerOfTen(-1 * Math.max(sigFigsA, sigFigsB));
return diff.compareTo(epsilon) < 0;
}
}

public static int getSignificantFigs(double inputDouble) {
// remove any exponent
BigDecimal input = new BigDecimal("" + Math.abs(inputDouble))
.stripTrailingZeros();
if (input.scale() < 0) {
int exponent = new Double(
Math.log10(Math.abs(inputDouble)))
.intValue();
input = input.scaleByPowerOfTen(-1 * exponent);
}
return input.precision();
}


And some tests:



@Test
public void testDoubleComparisonOnePositiveOneNegative() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.234E300D,
-1.234E300D
), "because one's positive and one's negative");
}

@Test
public void testDoubleComparisonZeroes() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
0D,
0.0D
), "zeroes");
}

@Test
public void testDoubleComparisonBasicDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
2.3450D,
2345.0D
), "typical numbers");
}

@Test
public void testDoubleComparisonMassivelyDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E-300D
), "big number vs tiny number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers2() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.2345678901234E300D,
1.2345678901233E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers3() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE
), "big number equals");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE * 0.1
), "big number");
}

@Test
public void testDoubleComparisonHugeNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
-1.2345678901234E300D,
-1.2345678901233E300D
), "big negative numbers");
}

@Test
public void testDoubleComparisonTinyPositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012345E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012344E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyTinyNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.5E-322D,
1.4E-322D
), "tiny tiny number");
}

@Test
public void testDoubleComparisonTinyTinyTinyNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL
), "tiny tiny number");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL * 0.1
), "tiny tiny numbers not same");
}

@Test
public void testDoubleComparisonThirds() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.3333333333333333333333333333333333333333D,
1.3333333333333333333333333333333333333333D
), "thirds");
}





share|improve this answer













public static boolean nearlyEqual(double a, double b) {
if (a == b) {
return true;
} else if (a == 0 || b == 0) {
return false;
} else {
BigDecimal diff = new BigDecimal("" + a)
.subtract(new BigDecimal("" + b))
.abs();
int exponentA = new Double(Math.log10(Math.abs(a))).intValue();
int exponentB = new Double(Math.log10(Math.abs(b))).intValue();
int sigFigsA = getSignificantFigs(a);
int sigFigsB = getSignificantFigs(b);
BigDecimal epsilon = new BigDecimal("0.1")
.scaleByPowerOfTen(Math.min(exponentA, exponentB))
.scaleByPowerOfTen(-1 * Math.max(sigFigsA, sigFigsB));
return diff.compareTo(epsilon) < 0;
}
}

public static int getSignificantFigs(double inputDouble) {
// remove any exponent
BigDecimal input = new BigDecimal("" + Math.abs(inputDouble))
.stripTrailingZeros();
if (input.scale() < 0) {
int exponent = new Double(
Math.log10(Math.abs(inputDouble)))
.intValue();
input = input.scaleByPowerOfTen(-1 * exponent);
}
return input.precision();
}


And some tests:



@Test
public void testDoubleComparisonOnePositiveOneNegative() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.234E300D,
-1.234E300D
), "because one's positive and one's negative");
}

@Test
public void testDoubleComparisonZeroes() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
0D,
0.0D
), "zeroes");
}

@Test
public void testDoubleComparisonBasicDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
2.3450D,
2345.0D
), "typical numbers");
}

@Test
public void testDoubleComparisonMassivelyDifferentNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E-300D
), "big number vs tiny number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789E300D,
1.23456789E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers2() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.2345678901234E300D,
1.2345678901233E300D
), "big number");
}

@Test
public void testDoubleComparisonHugePositiveNumbers3() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE
), "big number equals");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MAX_VALUE,
Double.MAX_VALUE * 0.1
), "big number");
}

@Test
public void testDoubleComparisonHugeNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
-1.2345678901234E300D,
-1.2345678901233E300D
), "big negative numbers");
}

@Test
public void testDoubleComparisonTinyPositiveNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012345E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyNegativeNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.23456789012345E-300D,
1.23456789012344E-300D
), "tiny number");
}

@Test
public void testDoubleComparisonTinyTinyNumbers() {
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
1.5E-322D,
1.4E-322D
), "tiny tiny number");
}

@Test
public void testDoubleComparisonTinyTinyTinyNumbers() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL
), "tiny tiny number");
Assertions.assertFalse(
GeneralUtils.nearlyEqual(
Double.MIN_NORMAL,
Double.MIN_NORMAL * 0.1
), "tiny tiny numbers not same");
}

@Test
public void testDoubleComparisonThirds() {
Assertions.assertTrue(
GeneralUtils.nearlyEqual(
1.3333333333333333333333333333333333333333D,
1.3333333333333333333333333333333333333333D
), "thirds");
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 27 '18 at 15:18









AdamAdam

2,28512252




2,28512252













  • I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

    – Milo Bem
    Nov 27 '18 at 17:31



















  • I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

    – Milo Bem
    Nov 27 '18 at 17:31

















I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

– Milo Bem
Nov 27 '18 at 17:31





I'm confused on what are you trying to achieve here. You basically reimplemented equals. Is there any case when different numbers return true, as in "nearly equal"?

– Milo Bem
Nov 27 '18 at 17:31


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449095%2foh-no-not-again-comparing-two-bowls-of-petunias-sorry-floats-for-equality%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Wiesbaden

Marschland

Dieringhausen