-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example where 1/3 + 1/3 != 2/3 #63
Comments
This is a good argument for pursuing BigDecimal instead of Decimal128, or at the very least support for the proposed behavior of throwing TypeError for use of the |
Ha-ha I believe it’s not possible with BigDecimal too. Warn about precision issue in readme section will be enough. If you want full precision for any expression, it’s possible with symbolic computation. But this is another topic. |
The BigDecimal option in the proposal forbids to use the I agree with @leebyron here that it's a good argument in favor of explicit division methods (possibly with a required precision parameter) instead of a In my opinion, an important reason to use something like |
Thanks for clarifying, looks legit. |
There are countless examples like this where 128-bit floats won't deliver an exact result. When we make these examples, I think we're thinking of One way to "rescue" Decimal128 from counterexamples like these would be to use an equality relation with a specified error tolerance. Imagine an What do you think? (I say this as someone who, personally, prefers the arbitrary-precision approach. I'm just saying here this apparent flaw of Decimal128 is perhaps not as fatal as it might appear.) |
Just to add to my previous comment: you can use a language that has Decimal128 support to see that the import java.math.BigDecimal;
public class FractionSum {
public static void main(String[] args) {
BigDecimal one = new BigDecimal("1");
BigDecimal two = new BigDecimal("2");
BigDecimal three = new BigDecimal("3");
BigDecimal nine = new BigDecimal("9");
BigDecimal a = one.divide(nine, java.math.MathContext.DECIMAL128);
BigDecimal b = two.divide(nine, java.math.MathContext.DECIMAL128);
BigDecimal c = a.add(b, java.math.MathContext.DECIMAL128);
BigDecimal d = three.divide(nine, java.math.MathContext.DECIMAL128);
System.out.println(c.toString());
System.out.println(d.toString());
System.out.println(d.equals(c) ? "yes" : "no");
}
} Running this:
|
Yea, proper example is differ.
With java it will give this result
|
Good example! I guess somewhat bigger numbers (denominators, that is) are needed to illustrate the issue. The larger point remains: Decimal128 is definitely going to fail on all sorts of cases that BigDecimal handles correctly. But if one knows that in advance, a different approach to equality can be recommended, and which (probably) does the job. Here's an updated Java snippet that illustrates what I have in mind with error tolerance: import java.math.BigDecimal;
public class Decimal {
private static BigDecimal tolerance = new BigDecimal("0.0000000001");
public static boolean almostEqual(BigDecimal a, BigDecimal b)
{
return -1 == a.add(b.negate()).abs().compareTo(tolerance);
}
public static void main(String[] args) {
BigDecimal one = new BigDecimal("1");
BigDecimal two = new BigDecimal("2");
BigDecimal three = new BigDecimal("3");
BigDecimal nine = new BigDecimal("31");
BigDecimal a = one.divide(nine, java.math.MathContext.DECIMAL128);
BigDecimal b = two.divide(nine, java.math.MathContext.DECIMAL128);
BigDecimal c = a.add(b, java.math.MathContext.DECIMAL128);
BigDecimal d = three.divide(nine, java.math.MathContext.DECIMAL128);
System.out.println(c.toString());
System.out.println(d.toString());
System.out.println(d.equals(c) ? "equal" : "not equal");
System.out.println(almostEqual(d, c) ? "almost equal" : "not almost equal");
}
} Here's I've implemented a very simple "almost equals" comparison: is
|
"almost equal" is practical solution if you know that you have not so many floating point operation. But each FLOP can accumulate round-to-nearest-even rounding and potentially can be bigger than epsilon? |
(...gradually returning to the discussion) I took a look at your initial example and wondered if I misunderstood something important. What do you mean by "in another base", in the original question? Are you thinking of bases other than 10, similar to the discussion in #75? |
I'm aware that An example of what NOT to do: Jest's |
There some rumours that Decimal128 is silver bullet. But we can construct expression similar to
But in another base. This will be fair to add it in readme.
The text was updated successfully, but these errors were encountered: