Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
assert 1.200065d.class == Double
assert 1.234f.class == Float
assert (-1.23E23D).class == Double
assert (1.167g).class == BigDecimal
    //Althoughalthough g suffix forhere BigDecimals is optional, it makes examples more readable

...

Code Block
assert (1f / 0f) == Double.POSITIVE_INFINITY
assert (-1f / 0f) == Double.NEGATIVE_INFINITY
assert Double.POSITIVE_INFINITY == Float.POSITIVE_INFINITY

assert 0.0f != -(0.0f)
    //positive and negative zeroes are not equal, when negative is written -(0.0f)
...
assert 0.0f == -0.0f
    //... but when negative is written -0.0f, it's evaluated as positive

...

There's a special variable called Double.NaN (and Float.NaN), meaning "Not a Number", which is sometimes returned from math calculations. Once introduced into a math calculation, the result will (usually) be NaN.

Conversions

The Float and Double classes, along with BigDecimal, BigInteger, Integer, Long, Short, and Byte, can all be converted to one another.

...

Code Block
assert 789g as Float == 789f
assert 45i.toFloat() == 45f //method name
assert 789g.toFloat() == 789f
assert 789g.floatValue() == 789f //alternative method name
assert 45i as double == 45d
assert 6789g.toDouble() == 6789d //method name
assert 6789g.doubleValue() == 6789d //alternative method name

assert new BigInteger( '1' + '0'*40 ).floatValue() == Float.POSITIVE_INFINITY
    //one with 40 zeroes after it
assert new BigInteger( '1234567890' * 3 ).floatValue() == 1.2345679e29f
    //precision lost on conversion

...

Code Block
assert 89.980 as float == 89.98f
assert 1.432157168 as float == 1.4321572f //rounded
assert 78.9g.toFloat() == 78.9f
assert 456.789g.floatValue() == 456.789f
assert 6.789g.toDouble() == 6.789d
assert 2345.6789g.doubleValue() == 2345.6789d
assert new BigDecimal( '-' + '1' *45 ).floatValue() == Float.NEGATIVE_INFINITY
assert new BigDecimal( '0.' + '0'*45 + '1' ).floatValue() == 0.0f
assert new BigDecimal( '0.' + '1234567890' *3 ).floatValue() == 0.12345679f
                                                //precision lost on conversion

...

Code Block
[ '77', '1.23e-23', '4.56', '-1.7E1', '98.7e2', '-0.27e-30' ].each{
  assert it.toFloat()
  assert new Float(it)
  assert it.toDouble()
  assert new Double(it)
}
assert new Float( '   1.23e-23    ' ) //leading and trailing whitespace removed
try{ new Float( null ); assert 0 }
catch(e){ assert e instanceof NullPointerException }
[ 'NaN', '-NaN', 'Infinity', '-Infinity', '+Infinity' ].each{
  assert new Float(it)
}

assert new Float( '  -0Xabc.defP7' )
    //we can have hexadecimal mantissa, with P indicating exponent
assert new Float( '  0xABC.DEFp17  ' )
    //part after P must be base-10, not more hex
assert new Float( '0X.defP-3f  \n' )
    //any whitespace OK (spaces, tabs, newlines, carriage returns, etc)
try{ new Float( '  @0X6azQ/3d' ); assert 0 }
catch(e){ assert e instanceof NumberFormatException }
    //because the string doesn't contain a parsable number in the form of a Float
assert Float.valueOf( '0xABp17' )
    //alternate means of contructing float from string representation
assert Float.parseFloat( '0xABp17' )
    //another alternate means of contructing float from string
assert new Double( '0x12bc.89aP7d  ' )

...

Code Block
assert new BigDecimal(0.25d) == 0.25
    //exact conversion because 0.25 has an exact binary representation

assert new BigDecimal(0.1d) ==
    0.1000000000000000055511151231257827021181583404541015625

(0.1d).toBigDecimal() == new BigDecimal(0.1d) //alternative method name

assert new BigDecimal(0.1f) == 0.100000001490116119384765625
    //inexact conversion as 0.1 has a recurring decimal part in binary

assert (0.1f as BigDecimal) == 0.100000001490116119384765625
ssert
assert new BigDecimal(0.1d, new java.math.MathContext(25) ) ==
    0.1000000000000000055511151 //rounds to 25 places as specified

...

Code Block
assert BigDecimal.valueOf( 0.25d ) == 0.25
assert BigDecimal.valueOf( 0.1d ) == 0.1
    //always exact, because converts double to a string first
assert new BigDecimal( Double.toString( 0.1d ) ) == 0.1
    //explicitly convert double to string, then to BigDecimal
assert BigDecimal.valueOf( -23.456e-17d ) == -2.3456E-16
assert BigDecimal.valueOf( -23.456e-17f ) == -2.3455999317674643E-16
    //result inexact because float converted to double first

try{ BigDecimal.valueOf( Double.POSITIVE_INFINITY ); assert 0 }
catch(e){ assert e instanceof NumberFormatException }

try{ BigDecimal.valueOf( Double.NaN ); assert 0 }
catch(e){ assert e instanceof NumberFormatException }
    //however, infinities and NaN won't convert that way

...

Code Block
assert Float.toString( 3.0e6f ) == '3000000.0' //no leading zeros
assert Float.toString( 3.0e0f ) == '3.0' //at least one digit after the point
assert Float.toString( 3.0e-3f ) == '0.0030'
assert Float.toString( 3.0e7f ) == '3.0E7'
    //exponent used if it would be > 6 or < -3
assert Float.toString( 3.0e-4f ) == '3.0E-4' //mantissa >= 1 and < 10

We can also convert a float or double to a hexadecimal string representation:

Code Block
[                      0.0f: '0x0.0p0',
                    (-0.0f): '0x0.0p0', //no negative sign in hex string rep'n of -0.0f
                       1.0f: '0x1.0p0', //most returned strings begin with '0x1.' or '-0x1.'
                       2.0f: '0x1.0p1',
                       3.0f: '0x1.8p1',
                       5.0f: '0x1.4p2',
                    (-1.0f): '-0x1.0p0',
                       0.5f: '0x1.0p-1',
                      0.25f: '0x1.0p-2',
          (Float.MAX_VALUE): '0x1.fffffep127',
          (Float.MIN_VALUE): '0x0.000002p-126',
                       //low values beginning with '0x0.' are called 'subnormal'
  (Float.NEGATIVE_INFINITY): '-Infinity',
                (Float.NaN): 'NaN',
].each{ k, v->
  assert Float.toHexString(k) == v
}

Floating-Point Arithmetic

We can perform the same basic operations that integers and BigDecimal can:

Code Block
assert 3.4f.plus( 3.3f ) == 3.4f + 3.3f
assert 3.4f.minus( 2.1f ) == 3.4f - 2.1f
assert 3.0f.multiply( 3.1f ) == 3.0f * 3.1f
assert 3.0f.multiply( 3f ) == 3.0f * 3f
assert 3.0.multiply( 3f ) == 3.0 * 3f
assert 7.7f.negate() == -7.7f //unary operation/method
assert (-7.7f).negate() == -(-7.7f)
assert +(7.7f) == 7.7f

try{ 3.4f.multiply(null); assert false }
catch(e){ assert e instanceof NullPointerException }
    //methods throw NullPointerException if passed a null

...

Code Block
assert 2.4f.div( 1.6f ) == ( 2.4f / 1.6f )
assert ( 2.5f / 1i ).class == Double
    //produces double result if either operand is float or double
assert ( 2.5f / 1.25 ).class == Double

...

Code Block
def Infinity=Double.POSITIVE_INFINITY, NaN=Double.NaN, Zero=0.0d
assert Math.IEEEremainder( 33d, 10d ) == 3d
                               //give remainder after rounding to nearest value
assert Math.IEEEremainder( 37d, 10d ) == -3d
assert Math.IEEEremainder( -33d, 10d ) == -3d
assert Math.IEEEremainder( -37d, 10d ) == 3d
assert Math.IEEEremainder( 35d, 10d ) == -5d
                               //when two values equally near, use even number
assert Math.IEEEremainder( 45d, 10d ) == 5d
assert Math.IEEEremainder( Zero, 10d ) == Zero
assert Math.IEEEremainder( -Zero, 10d ) == -Zero
assert Math.IEEEremainder( Infinity, 10d ) == NaN
assert Math.IEEEremainder( 35d, Zero ) == NaN
assert Math.IEEEremainder( 35d, Infinity ) == 35d

...

Code Block
assert 345f.equals( 3.45e2f ) && 345f == 3.45e2f
    //equals() and == behave the same in all cases
assert ! 34.5f.equals( 13.4f ) && 34.5f != 13.4f //equivalent

assert Float.NaN.equals( Float.NaN ) && Float.NaN == Float.NaN

assert 0.0f == -0.0f && 0.0f.equals( -0.0f )
    //-0.0f is evaluated as positive zero
assert 0.0f != -(0.0f) && ! 0.0f.equals( -(0.0f) )
    //negative zero must be written -(0.0f)

assert 345d.equals( 3.45e2d ) && 345d == 3.45e2d

assert Float.POSITIVE_INFINITY.equals( Float.POSITIVE_INFINITY ) &&
    Float.POSITIVE_INFINITY == Float.POSITIVE_INFINITY
assert ! Float.POSITIVE_INFINITY.equals( Float.NEGATIVE_INFINITY ) &&
    ! ( Float.POSITIVE_INFINITY == Float.NEGATIVE_INFINITY )

...

Code Block
assert (2.50f <=> 2.5f) == 0 && 2.50f.compareTo(2.5f) == 0
assert (-3.45f <=> 1.23f) == -1 && (-3.45f).compareTo(1.23f)  == -1
assert (1.23d <=> -0.12d) == 1 && 1.23d.compareTo(-0.12d) == 1
assert (-1.23d < -0.12d) && (-1.23d).compareTo(-0.12d) < 0

assert (Float.NaN > Float.POSITIVE_INFINITY) &&
    Float.NaN.compareTo(Float.POSITIVE_INFINITY) > 0
assert (0.0f <=> -0.0f) == 0
assert (Float.NaN <=> Float.NaN) == 0 && Float.NaN.compareTo(Float.NaN) == 0
assert Float.compare( 3.4f, 7.9f ) == -1
assert Double.compare( 3.4d, -7.9d ) == 1

...

Code Block
assert (1.23d? true: false)
assert ! (0.0f? true: false)

Bitwise Operations

We can convert a float to the equivalent int bits, or a double to equivalent float bits. For a float, bit 31(mask 0x80000000) is the sign, bits 30-23 (mask 0x7f800000) are the exponent, and bits 22-0 (mask 0x007fffff) are the mantissa. For a double, bit 63 is the sign, bits 62-52 are the exponent, and bits 51-0 are the mantissa.

...

Code Block
assert Float.MAX_VALUE == Float.intBitsToFloat(0x7f7fffff)
assert Float.MIN_NORMAL == Float.intBitsToFloat(0x00800000)
    //the smallest positive nonzero normal value
assert Float.MIN_VALUE == Float.intBitsToFloat(0x1)
    //the smallest positive nonzero value, including subnormal values
assert Float.MAX_EXPONENT == Math.getExponent(Float.MAX_VALUE)
assert Float.MIN_EXPONENT == Math.getExponent(Float.MIN_NORMAL)
assert Float.MIN_EXPONENT == Math.getExponent(Float.MIN_VALUE) + 1
    //for subnormal values

Floating-Point Calculations

There are two constants of type Double, Math.PI and Math.E, that can't be represented exactly, not even as a recurring decimal.

...

Code Block
assert Math.ulp( 123.456d ) == Math.ulp( -123.456d )
assert Math.ulp( 0.123456789d ) != Math.ulp( 0.123456789f )
    //if Float, a different scale is used

assert Math.ulp( Double.POSITIVE_INFINITY ) == Double.POSITIVE_INFINITY
assert Math.ulp( Double.NEGATIVE_INFINITY ) == Double.POSITIVE_INFINITY
assert Math.ulp( 0.0d ) == Double.MIN_VALUE
assert Math.ulp( Double.MIN_VALUE ) == Double.MIN_VALUE
assert Double.MAX_VALUE > Math.ulp( Double.MAX_VALUE )

Accuracy of the Math methods is measured in terms of such ulps for the worst-case scenario.If a method always has an error less than 0.5 ulps, the method always returns the floating-point number nearest the exact result, and so is always correctly rounded. However, doing this and maintaining floating-point calculation speed together is impractical. Instead, for the Math class, a larger error bound of 1 or 2 ulps is allowed for certain methods. But most methods with more than 0.5 ulp errors are still required to be semi-monotonic, ie, whenever the mathematical function is non-decreasing, so is the floating-point approximation, and vice versa. Not all approximations that have 1 ulp accuracy meet the monotonicity requirements. sin, cos, tan, asin, acos, atan, exp, log, and log10 give results within 1 ulp of the exact result that are semi-monotonic.

Further Calculations

We can find the polar coordinate of two (x,y) coordinates. The result is within 2 ulps of the exact result, and is semi-monotonic.

Code Block
def Infinity= Double.POSITIVE_INFINITY, NaN= Double.NaN, Zero= 0.0d

[     [ 1d, 1d ]: 0.25d * Math.PI,
     [ 1d, -1d ]: 0.75d * Math.PI,
     [ -1d, 1d ]: -0.25d * Math.PI,
    [ -1d, -1d ]: -0.75d * Math.PI,

      [ 0d, 1d ]: 0d,
   [ -(0d), 1d ]: -(0d),
     [ 0d, -1d ]: Math.PI,
  [ -(0d), -1d ]: -Math.PI, // -(0d) instead of 0d gives huge difference in result to 0d 
      [ 1d, 0d ]: 0.5d * Math.PI,
   [ 1d, -(0d) ]: 0.5d * Math.PI,
     [ -1d, 0d ]: -0.5d * Math.PI,
  [ -1d, -(0d) ]: -0.5d * Math.PI,

        [ Double.NaN, 1d ]: Double.NaN, //NaN returned if either argument is NaN

          [ 1d, Infinity ]: 0d,
         [ 1d, -Infinity ]: Math.PI,
         [ -1d, Infinity ]: -(0d),
        [ -1d, -Infinity ]: -Math.PI,
          [ Infinity, 1d ]: 0.5d * Math.PI,
         [ Infinity, -1d ]: 0.5d * Math.PI,
         [ -Infinity, 1d ]: -0.5d * Math.PI,
        [ -Infinity, -1d ]: -0.5d * Math.PI,
    [ Infinity, Infinity ]: 0.25d * Math.PI,
   [ Infinity, -Infinity ]: 0.75d * Math.PI,
   [ -Infinity, Infinity ]: -0.25d * Math.PI,
  [ -Infinity, -Infinity ]: -0.75d * Math.PI,
].each{k,v->
  if( Math.atan2( k[0], k[1] ) != v )
        println "( ${k[0]}, ${k[1]} ): ${Math.atan2(k[0],k[1])};  $v"
}

...

Code Block
assertClose= {it1,it2,ulp->
  assert it1 > it2 - ulp*Math.ulp(it2) && it1 < it2 + ulp*Math.ulp(it2)
}
def Infinity=Double.POSITIVE_INFINITY, Zero=0d, NaN=Double.NaN, E=Math.E
assertClose Math.sinh( 2d ), 0.5d*(E**2d - E**-2d), 2.5d
    //sinh() result will be with 2.5 ulp of exact value
assert Math.sinh( Infinity ) == Infinity
assert Math.sinh( -Infinity ) == -Infinity
assert Math.sinh( Zero ) == Zero
assert Math.sinh( -Zero ) == -Zero
assertClose Math.cosh( 2d ), 0.5d*(E**2d + E**-2d), 2.5d
assert Math.cosh( Infinity ) == Infinity
assert Math.cosh( -Infinity ) == Infinity
assert Math.cosh( Zero ) == 1d
assert Math.cosh( -Zero ) == 1d
assertClose Math.tanh( 2d ), Math.sinh( 2d )/Math.cosh( 2d ), 2.5d
assert Math.tanh( Infinity ) == 1d
assert Math.tanh( -Infinity ) == -1d
assert Math.tanh( Zero ) == Zero
assert Math.tanh( -Zero ) == -Zero
    //once the exact result of tanh is within 1/2 of an ulp of 
    //the limit value of +/- 1, a correctly signed +/- 1.0 will be returned

...

Code Block
assert Math.toDegrees( Math.PI ) == 180.0
assert Math.toRadians( 90.0 ) == 0.5 * Math.PI

We can calculate (E**x)-1 (1 + x) in one call. For values of x near 0, Math.expm1( x ) + 1d is much closer than Math.exp( x ) to the true result of e**x. The result will be semi-monotonic, and within 1 ulp of the exact result. Once the exact result of e**x - 1 is within 1/2 ulp of the limit value -1, -1d will be returned.

...

Code Block
assert Math.ceil( 6.77 ) == 7; assert &&      Math.floor( 6.77 ) == 6
assert Math.ceil( -34.43 ) == -34; assert&&  Math.floor( -34.43 ) == -35
assert Math.ceil( 0.73 ) == 1.0; assert&&    Math.floor( 0.73 ) == 0.0
assert Math.ceil( -0.73 ) == -0.0d; assert&& Math.floor( -0.73 ) == -1.0
    //sign required for -0.0d
assert Math.ceil( 13.0 ) == 13.0; assert&&   Math.floor( 13.0 ) == 13.0
assert Math.ceil( 0.0 ) == 0.0; &&     Math.floor( 0.0 ) == 0.0
assert Math.ceil( 23.45 ) == -Math.floor( -23.45 )
    //Math.ceil(x) always equals -Math.floor(-x)

...

Code Block
[   7.49d: 7.0d,
     7.5d: 8.0d,
     8.5d: 8d,
  (-7.5d): -8d,
       7d: 7d,
       0d: 0d,
 (Double.POSITIVE_INFINITY): Double.POSITIVE_INFINITY,
].each{ k, v-> assert Math.rint( k ) == v }
    //round to nearest integer (or even integer)

assert Math.abs( -23i ) == 23i
assert Math.abs( 234L ) == 234L
assert Math.abs( 0i ) == 0i
assert Math.abs( Integer.MIN_VALUE ) == Integer.MIN_VALUE
                              //WARNING: this result not intuitive
assert Math.abs( Long.MIN_VALUE ) == Long.MIN_VALUE

assert Math.abs( -23.45f ) == 23.45f
assert Math.abs( -123.4d ) == 123.4d
assert Math.abs( 0.0f ) == 0.0f
assert Math.abs( -0.0f ) == 0.0f
assert Math.abs( Float.NEGATIVE_INFINITY ) == Float.POSITIVE_INFINITY 

[ -23.45f, 781.23f, Float.NEGATIVE_INFINITY ].each{
  assert Math.abs(it) ==
      Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(it))
  assert Math.abs(it) ==
      Float.intBitsToFloat((Float.floatToIntBits(it)<<1)>>>1) 
} //there's related assertions for doubles

...

Code Block
def Infinity= Double.POSITIVE_INFINITY, NaN= Double.NaN
[
  [ 3d, 0d ]: 1d,
  [ 3d, -(0d) ]: 1d,
  [ 3d, 1d ]: 3d,
  [ 3d, Infinity ]: Infinity,
  [ -3d, Infinity ]: Infinity,
  [ 0.3d, -Infinity ]: Infinity,
  [ -0.3d, -Infinity ]: Infinity,
  [ 3d, -Infinity ]: 0d,
  [ -3d, -Infinity ]: 0d,
  [ 0.3d, Infinity ]: 0d,
  [ -0.3d, Infinity ]: 0d,
  [ 1d, Infinity ]: Double.NaN,
  [ 0d, 1d ]: 0d,
  [ Infinity, -1d ]: 0d,
  [ 0d, -1d ]: Infinity,
  [ Infinity, 1d ]: Infinity,
  [ -(0d), 2d ]: 0d, //exponent >0 but not finite odd integer
  [ -Infinity, -2d ]: 0d, //exponent <0 but not finite odd integer
  [ -(0d), 3d ]: -(0d), //exponent is positive finite odd integer
  [ -Infinity, -3d ]: -(0d), //exponent is negative finite odd integer
  [ -(0d), -2d ]: Infinity, //exponent <0 but not finite odd integer
  [ -Infinity, 2d ]: Infinity, //exponent >0 but not finite odd integer
  [ -(0d), -3d ]: -Infinity, //exponent is negative finite odd integer
  [ -Infinity, 3d ]: -Infinity, //exponent is positive finite odd integer
  [ -3d, 4i ]: {-> def a= Math.abs(-3d); a*a*a*a }(),
                                //exponent is finite even integer
  [ -3d, 5i ]: {-> def a= Math.abs(-3d); -a*a*a*a*a }(),
                                //exponent is finite odd integer
  [ -3d, 2.5 ]: NaN, //exponent is finite and not an integer
  [ NaN, 0d ]: 1d //exception to the NaN ripple rule
].each{k, v->
  assert Math.pow( k[0], k[1] ) == v
}

...

Code Block
def Infinity=Double.POSITIVE_INFINITY, Zero=0d, NaN=Double.NaN, E=Math.E
assert Math.getExponent(2.345e31d) <= Double.MAX_EXPONENT
assert Math.getExponent(2.345e31d) >= Double.MIN_EXPONENT
assert Math.getExponent( NaN ) == Double.MAX_EXPONENT + 1
assert Math.getExponent( Infinity ) == Double.MAX_EXPONENT + 1

assert Math.getExponent( Zero ) == Double.MIN_EXPONENT - 1
    //this is also the value of subnormal exponents

assert Math.getExponent(12.3e4f) <= Float.MAX_EXPONENT &&
    Math.getExponent(12.3e4f) >= Float.MIN_EXPONENT

...

Code Block
def Infinity=Double.POSITIVE_INFINITY, NaN=Double.NaN, Zero= 0d
assert Math.nextAfter( 12.34d, 999d ) == 12.34d + Math.ulp( 12.34d )
assert Math.nextAfter( 12.34d, -999d ) == 12.34d - Math.ulp( 12.34d )
assert Math.nextAfter( 12.34f, 999f ) == 12.34f + Math.ulp( 12.34f )
assert Math.nextAfter( 12.34d, 12.34d ) == 12.34d
    //if numbers equal, return second one
assert Math.nextAfter( Zero, -Zero ) == -Zero
    //numbers are 'equal', and second one returned
assert Math.nextAfter( Double.MIN_VALUE, -12d ) == Zero
assert Math.nextAfter( -Double.MIN_VALUE, 12d ) == -Zero
assert Math.nextAfter( Double.MAX_VALUE, Infinity ) == Infinity
assert Math.nextAfter( -Double.MAX_VALUE, -Infinity ) == -Infinity
assert Math.nextAfter( Infinity, 12d ) == Double.MAX_VALUE
assert Math.nextAfter( -Infinity, 12d ) == -Double.MAX_VALUE
assert Math.nextAfter( Zero, Infinity ) == Double.MIN_VALUE
assert Math.nextAfter( Infinity, Infinity ) == Infinity
assert Math.nextUp( 12.34d ) == Math.nextAfter( 12.34d, Infinity )
    //shortcut method for both doubles and floats

...