Skip to content
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

scala.Double.Epsilon is set to wrong value #3791

Closed
scabug opened this issue Aug 24, 2010 · 22 comments
Closed

scala.Double.Epsilon is set to wrong value #3791

scabug opened this issue Aug 24, 2010 · 22 comments
Assignees
Milestone

Comments

@scabug
Copy link

@scabug scabug commented Aug 24, 2010

It's description says: "The smallest difference between two values of Double." However, if you look up its value it's set to java.lang.Double.MIN_VALUE.

The smallest difference between two Doubles is a lot bigger then the smallest value that can be stored in a Double.

Here's an exempt from "float.h":

#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */

#define DBL_MIN 2.2250738585072014e-308 /* min positive value */

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 24, 2010

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 31, 2010

@lrytz said:

scala> scala.Double.MinValue == -java.lang.Double.MAX_VALUE
res0: Boolean = true

scala> scala.Double.Epsilon == java.lang.Double.MIN_VALUE 
res1: Boolean = true

where did you find the description "The smallest difference between two values of Double." However, if you look up its value it's set to java.lang.Double.MIN_VALUE"?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 31, 2010

@retronym said:
The description is on the doc comment of [https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_0_final/src/library/scala/Math.scala#L76 scala.Math.EPS_DOUBLE], which is deprecated with a pointer to Double.Epsilon. Double.Epsilon itself is not part of the API documentation.

This is the accepted meaning of epsilon. Apache Commons Math defines it as:

class MathUtils {
/** Smallest positive number such that 1 - EPSILON is not numerically equal to 1. */
    public static final double EPSILON = 0x1.0p-53;

Usage:

scala> import org.apache.commons.math.util.MathUtils
import org.apache.commons.math.util.MathUtils

scala> (1d - Double.Epsilon) == 1d
res18: Boolean = true

scala> (1d - MathUtils.EPSILON) == 1d
res19: Boolean = false

scala> (1d - MathUtils.EPSILON / 2) == 1d
res20: Boolean = true

scala>  MathUtils.EPSILON
res21: Double = 1.1102230246251565E-16

I guess the deviation from the names used in Java stemmed from the confusing name MIN_VALUE, which could be interpreted as -MAX_VALUE or the smallest positive value. But epsilon is the wrong name for this value.

Proposal:

  • Change Double.Epsilon to the value defined by Apache Commons Math, with a migration warning.
  • Add Double.MinPositiveValue = java.lang.Double.MIN_VALUE
  • Add Double.MinNegativeValue = -Double.MaxValue
  • Deprecate Double.MinValue, rather than leave it a different meaning from java.lang.Double.MIN_VALUE, with which Java developers may be familiar.
  • Do the same for the other AnyVal companion objects.
  • Remove the already deprecated constants from scala.Math.
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 31, 2010

@harrah said:
I agree with Jason, although I think it would be better to deprecate Epsilon and add a new val Eps. For the record, the change to the constants appears to have occurred in r9506.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 31, 2010

@retronym said:
For comparison, here are the C++ versions: http://www.cplusplus.com/reference/std/limits/numeric_limits/

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 1, 2010

@gbasler said:
Thanks Jason for elaborating on this!

I am wondering why the c++ libraries define Epsilon as 2.2e-016 and Apache Commons Math uses 1.1e-16. Apparently the difference is in the definition, e.g.:

scala> import org.apache.commons.math.util.MathUtils
import org.apache.commons.math.util.MathUtils

scala> (1d - MathUtils.EPSILON) == 1d
res4: Boolean = false

scala> (1d - MathUtils.EPSILON/2) == 1d
res5: Boolean = true

scala> (1d + MathUtils.EPSILON) == 1d
res6: Boolean = true

scala> (1d + 2*MathUtils.EPSILON) == 1d
res7: Boolean = false

Apache Commons Math: 1 - EPSILON != 1
C++ headers: 1 + EPSILON != 1

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 7, 2010

@TiarkRompf said:
Lukas, do you want to follow up on this?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 7, 2010

@retronym said:
I'd also be happy with Mark's suggestion. Although I expect the number of people using Double.Epsilon would be somewhere within a machine epsilon of zero :)

We could always go with Double.ε ;D

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 9, 2010

@lrytz said:
(In r22957) close #3791 according to jason's proposal. Epsilon is just deprecated for now; for changing it, it needs to go through the
long cycle (deprecate, remove, add with new behavior). I tried adding Scaladoc for these members but failed for now, see
my message in internals.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 9, 2010

@retronym said:
addModuleMethod(FloatClass, "MinPositiveValue", -java.lang.Float.MAX_VALUE)

should be

addModuleMethod(FloatClass, "MinPositiveValue", java.lang.Float.MIN_VALUE)

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 9, 2010

@lrytz said:
(In r22959) fix fix for (close #3791) and made deprecation for constants work. no review.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Feb 15, 2011

@retronym said:
Outcome of the recent discussion:

  • undeprecate MinValue
  • remove MinNegativeValue
  • retain MinPositiveValue, and deprecation of Epsilon.

My 2c:

  • Add Scaladoc to Double/Float MinValue to higlight that they are different from the same named constants in Java.
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Mar 2, 2011

@paulp said:
Raising to high to make sure it's in 2.9.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Mar 9, 2011

@soc said:
I made the changes, pull request here: [https://github.com/scala/scala/pull/7]

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Mar 15, 2011

@paulp said:
(In r24461) Addresses the issues swirling around Double.Epsilon and friends
which were battled out in more than one venue and then aptly summarized
by retronym in #3791. Thanks to Simon Ochsenreither for submitting
a patch; I wasn't able to use too much of it because the source
code for these types is generated, but effort is always
appreciated. Closes #3791, and I'm tired and I'd hate to blow
this one at this late date: review by rytz.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 7, 2012

@dgruntz said:
Float.Epsilon and Double.Epsilon have been removed in 2.10 (after having been deprecated in 2.9), so it is time to add the correct versions to 2.11.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 7, 2012

@dgruntz said:
Will add the constant Epsilon to the classes Double and Float as follows:

scala> final val Eps = java.lang.Double.longBitsToDouble(0x3ca0000000000000L)
Eps: Double = 1.1102230246251565E-16

scala> 1d+Eps == 1d
res1: Boolean = true

scala> 1d-Eps == 1d
res2: Boolean = false

scala> final val Eps = java.lang.Float.intBitsToFloat(0x33800000)
Eps: Float = 5.9604645E-8

scala> 1f+Eps == 1f
res3: Boolean = true

scala> 1f-Eps == 1f
res4: Boolean = false

This value gives an upper bound on the relative error due to rounding real numbers to floating point numbers (either Floats or Doubles). For any floating point system with base B and precision (or mantissa length) p this upper bound is defined as B^(-(p-1))/2 (which corresponds to 1/2 ulp = 1/2 unit in the last place).

  • Float (B=2 / p=24): Eps = 2^(-24)

  • Double (B=2 / p=53): Eps = 2^(-53)

The definition as the smallest value with 1+Eps != 1 or 1-Eps != 1 leads to slightly different values (if not only powers of 2 are considered). The following method computes the smallest value for 1+Eps != 1 for double precision, and you see, the result is the double number which is the neighbor of the above defined value for Epsilon.

scala> def epsilon = {
     |   def eps(a: Double, b: Double): Double = {
     |     val e = a + (b-a)/2
     |     if(a < e && e < b) {
     |       val f = 1 + e
     |       if(f == 1.0) eps(e, b) else eps(a, e)
     |     } else b
     |   }
     |   eps(0, 1)
     | }
epsilon: Double

scala> val eps = epsilon
eps: Double = 1.1102230246251568E-16

scala> 1d+eps==1d
res1: Boolean = false

scala> f"${java.lang.Double.doubleToLongBits(eps)}%x"
res2: String = 3ca0000000000001
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 7, 2012

@dgruntz said:
submitted scala/scala#1076.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Dec 3, 2014

Samuel Papin (spapin-at-twitter.com) said:
"The smallest difference between two values of Double." is java.double.Double.Min

scala> val a = java.lang.Double.MIN_VALUE
a: Double = 4.9E-324

scala> val b = 2*java.lang.Double.MIN_VALUE
b: Double = 1.0E-323

scala> a-b
res0: Double = -4.9E-324

And as the pull request on github tells defining a machine epsilon is really opinionated and most programmers would just make their own. Should this issue be closed?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Dec 3, 2014

@Ichoran said:
[~spapin@twitter.com] There is a perfectly well-defined meaning for this that isn't a matter of opinion at all; it's well-defined by IEEE 754. Whether it is useful is another matter. I'll look into it and either close the issue or fix it.

Thanks for calling attention to this.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Dec 4, 2014

@dgruntz said:
My proposal is to close this bug report. The bug originally reported has been fixed. It was not clear to me whether I can simply press the close issue button or whether some discussions have to be made somewhere.

Regarding the definition: Is it really defined in IEEE754? I just skimmed the spec, but did not find info about the machine epsilon, and on Wikipedia I found the sentence

The IEEE standard does not define the terms machine epsilon and unit roundoff, so differing definitions of these terms are in use, which can cause some confusion.

I remember two definitions:

  • the eps is defined to be the smallest float with the property 1+eps > 1. This definition leads to 5.960465E-8 (for float), or 1 100111 00000000000000000000001 in binary (or 2^(-24)*(1+2^(-23)))

  • the eps is defined to bhe the largest float with the property 1+eps = 1. This definition leads to 5.960465E-8 as well, or 1 100111 00000000000000000000000 in binary (or 2^(-24)

So I really come to the conclusion that the Scala library should not define such a constant.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Dec 18, 2014

@Ichoran said:
"Fixed" by removal (in a previous version). As @dgruntz points out, there is not complete consensus about which of the two obvious values for epsilon should be used. We now have none, which leaves it up to the user to pick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.