...
| 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 |
...