Why does Long.MaxValue fit in a Double but < Long.MaxValue not - scala

I know there is a simple answer for this but it has me puzzled.
Why is it that Long.MaxValue can be stored in a Double and returned as longValue, but a lesser Long loses precision.
I would have expected a loss of precision after 53 bits ? What is going on here
scala> val x:Double = Long.MaxValue // x: Double = 9.223372036854776E18 (9223372036854775807)
scala> x == Long.MaxValue // Boolean = true
scala> x.longValue == Long.MaxValue // Boolean = true
scala> val y = 1234567890123456789L // y: Long = 1234567890123456789 // less than Long.MaxValue
scala> y < x // Boolean = true
scala> val z:Double = y // z: Double = 1.23456789012345677E18
scala> z == y // Boolean = true
scala> z.longValue == y // Boolean = false // why ? MaxValue fits in the Double
scala> z.longValue // 1234567890123456768 <-- loss of 21

It's not a matter of "fitting". Doubles are just inherently inexact. Some values will be represented exactly, some won't. It looks like you found one that can be (your x) and one that can't (y).
It's not particular to the values you've chosen. Here's similar behavior with smaller values that clearly "fit" into Doubles:
val a = 1.1 // a: Double = 1.1
a == 1.1 // true
val b = 2.2 // b: Double = 2.2
b == 2.2 // true
val c = 1.1 + 2.2 // c: Double = 3.3000000000000003
c == 3.3 // false

It's actually not fitting, and it is losing precision.
But the loss is because it's being rounded up:
scala> BigDecimal.exact(Long.MaxValue.toDouble)
res0: scala.math.BigDecimal = 9223372036854775808
scala> Long.MaxValue
res1: Long = 9223372036854775807
What happens when you try to fit a too-big Double into a Long?
scala> 1e100.toLong
res2: Long = 9223372036854775807
It's truncated.
So Long.MaxValue is rounded up to 2^63 which can be represented exactly with 53 bits and a binary exponent, and since it's bigger than Long.MaxValue it turns back into Long.MaxValue when you convert to Long.

Related

Division giving odd results scala

I'm making a simple program to make a calculation for a game I play. I tried 2 attempts and it wasn't working. I made all the variables doubles but I still get this odd result.
The values of actionTicks would be 1-10, skillLevel would be 1-99.
My current output is :
Your chance of receiving a pet is: 1.6E-6
Your chance is 0
Could someone explain why the result is wrong and how I'd fix it.
import scala.io.StdIn._
object PetRates {
def main(args: Array[String]): Unit = {
var baseDiv: Double = 50000000
println("Enter amount of ticks per action: ")
var actionTicks = readDouble()
println("Now enter your skill level: ")
var skillLvl = readDouble()
var result: Double = actionTicks*skillLvl
println("Your chance is: " + (result / baseDiv))
println("Your chance is " + ((8 * 10)/50000000) )
}
}
Your app appears to have delivered exactly what you're asking it to. It looks like you might be confused by the scientific notation:
scala> (8.0 * 10.0) / 50000000.0
// res1: Double = 1.6E-6
scala> 0.0000016
// res2: Double = 1.6E-6
As to (8 * 10) / 50000000, it's an integer division returning an integer (that rounds towards 0) since the operands are all Int type:
scala> (8 * 10) / 50000000
// res3: Int = 0
scala> 40000000 / 50000000
// res4: Int = 0
scala> 80000000 / 50000000
// res5: Int = 1
scala> -40000000 / 50000000
// res5: Int = 0
To add to Leo's answer, you can write either of the terms in fractions as a double so that the result is also double, like
(8.0 * 10)/50000000)

How can I check whether a Double value overflows?

I want to check if adding some value to a double value exceed the Double limits or not. I tried this:
object Hello {
def main(args: Array[String]): Unit = {
var t = Double.MaxValue
var t2 = t+100000000
if(t2 > 0) {
println("t2 > 0: " + t2)
} else
println("t2 <= 0: " + t2)
}
}
The output I get is
t2 > 0: 1.7976931348623157E308
What I actually want is to sum billions of values and check whether or not the running sum overflows at any time.
The first part of your question seems to stem from a misunderstanding of floating-point numbers.
IEEE-754 floating-point numbers do not wrap around like some finite-size integers would. Instead, they "saturate" at Double.PositiveInfinity, which represents mathematical (positive) infinity. Double.MaxValue is the largest finite positive value of doubles. The next Double after that is Double.PositiveInfinity. Adding any double (other than Double.NegativeInfinity or NaNs) to Double.PositiveInfinity yields Double.PositiveInfinity.
scala> Double.PositiveInfinity + 1
res0: Double = Infinity
scala> Double.PositiveInfinity - 1
res1: Double = Infinity
scala> Double.PositiveInfinity + Double.NaN
res2: Double = NaN
scala> Double.PositiveInfinity + Double.NegativeInfinity
res3: Double = NaN
Floating-point numbers get fewer and farther between as their magnitude grows. Double.MaxValue + 100000000 evaluates to Double.MaxValue as a result of roundoff error: Double.MaxValue is so much larger than 100000000 that the former "swallows up" the latter if you try to add them. You would need to add a Double of the order of math.pow(2, -52) * Double.MaxValue to Double.MaxValue in order to get Double.PositiveInfinity:
scala> math.pow(2,-52) * Double.MaxValue + Double.MaxValue
res4: Double = Infinity
Now, you write
What I actually want is to sum billions of values and check whether or not the running sum overflows at any time.
One possible approach is to define a function that adds the numbers recursively but stops if the running sum is an infinity or a NaN, and wraps the result in an Either[String, Double]:
import scala.collection.immutable
def sumToEither(xs: immutable.Seq[Double]): Either[String, Double] = {
#annotation.tailrec
def go(ys: immutable.Seq[Double], acc: Double): Double =
if (ys.isEmpty || acc.isInfinite || acc.isNaN) acc
else go(ys.tail, ys.head + acc)
go(xs, 0.0) match {
case x if x.isInfinite => Left("overflow")
case x if x.isNaN => Left("NaN")
case x => Right(x)
}
}
In response to your question in the comments:
Actually, I want to get the total of billions of values and check if the total overflows anytime or not. Could you please tell a way to check that?
If the total overflows, the result will be either an infinity (either positive or negative), or NaN (if at some point you have added a positive and negative infinity): the easiest way is to check total.isInfinity || total.isNaN.

Why converting '1' char to int using toInt method results to 49?

I want to convert a char to an int value.
I am a bit puzzled by the way toInt works.
println(("123").toList) //List(1, 2, 3)
("123").toList.head // res0: Char = 1
("123").toList.head.toInt // res1: Int = 49 WTF??????
49 pops up randomly for no reason.
How do you convert a char to int the right way?
For simple digit to int conversions there is asDigit:
scala> "123" map (_.asDigit)
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
Use Integer.parseInt("1", 10). Note that the 10 here is the radix.
val x = "1234"
val y = x.slice(0,1)
val z = Integer.parseInt(y)
val z2 = y.toInt //equivalent to the line above, see #Rogach answer
val z3 = Integer.parseInt(y, 8) //This would give you the representation in base 8 (radix of 8)
49 does not pop up randomly. It's the ascii representation of "1". See http://www.asciitable.com/
.toInt will give you the ascii value. It's probably easiest to write
"123".head - '0'
If you want to handle non-numeric characters, you can do
c match {
case c if '0' <= c && c <= '9' => Some(c - '0')
case _ => None
}
You can also use
"123".head.toString.toInt

call a def within a block

If there is any way to call a def from a block
def factor (n: Int) : Int = if (n == 0 ) 1 else n * factor(n-1)
val i = 1000
i.toString.foreach ( x => sum += factor(x.toInt) )
at the end I want to get the sum of factorial of every digit
But it seems like def doesn't return a value, everytime is 0
How to fix it?
Thanks!
The problem actually has nothing to do with Scala per se; your code and your def are fine. The issue is with toInt:
scala> '3'.toInt
res7: Int = 51
toInt doesn't actually convert it as a decimal digit, but as a unicode (ish?) character value. These are producing very large numbers which go beyond what factor can handle:
scala> factor(6)
res8: Int = 720
scala> factor(20)
res9: Int = -2102132736
scala> factor(100)
res10: Int = 0
So instead use (thanks to Luigi)
x.asDigit

Number formatting in Scala?

I have a dynamically changing input reading from a file. The numbers are either Int or Double. Why does Scala print .0 after every Double number? Is there a way for Scala to print it the same way it reads it?
Example:
var x:Double = 1
println (x) // This prints '1.0', I want it to print '1'
x = 1.0 // This prints '1.0', which is good
I can't use Int because some of the input I get are Doubles. I can't use String or AnyVal because I perform some math operations.
Thank you,
scala> "%1.0f" format 1.0
res3: String = 1
If your input is either Int or Double, you can do it like this:
def fmt(v: Any): String = v match {
case d : Double => "%1.0f" format d
case i : Int => i.toString
case _ => throw new IllegalArgumentException
}
Usage:
scala> fmt(1.0)
res6: String = 1
scala> fmt(1)
res7: String = 1
scala> fmt(1.0f)
java.lang.IllegalArgumentException
at .fmt(<console>:7)
at .<init>(<console>:6)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:4)
at RequestResult$.<clinit>(<console>)
at RequestResult$result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.Dele...
Otherwise, you might use BigDecimals. They are slow, but they do come with the scale, so "1", "1.0" and "1.00" are all different:
scala> var x = BigDecimal("1.0")
x: BigDecimal = 1.0
scala> x = 1
x: BigDecimal = 1
scala> x = 1.0
x: BigDecimal = 1.0
scala> x = 1.000
x: BigDecimal = 1.0
scala> x = "1.000"
x: BigDecimal = 1.000
var x:Double = 1
var y:Double = 1.0
print(x) // => 1.0
print(y) // => 1.0
If i understand you question you want scala to print x and y differently? The problem is that x and y are both a variable of the type Double and look the same.
Why do you explicitly define the type of the vars?
var x = 1
var y= 1.0
print(x) // => 1
print(y) // => 1.0
Use printf:
printf("The value is %.0f", x)
For a description of the format string, see this page from the Java SE 6 API documentation.
Note that you can ofcourse also use the Java library from Scala, so other ways to format numbers from Java can also be used from Scala. You can for example use class java.text.DecimalFormat:
val df = new java.text.DecimalFormat("#####")
println(df.format(x))
Starting with Scala 2.10 you can use the f interpolator:
scala> val x: Double = 1
x: Double = 1.0
scala> println(f"$x%.0f")
1
scala> val i = 1
i: Int = 1
scala> println(f"$i%.0f")
1
The use of a "_.0" at the end of floating point numbers is a convention. Just a way to know that the number is actually floating point and not an integer.
If you really need to "to print it the same way it reads it" you may have to rethink the way your code is structured, possibly preserving your input data. If it's just a formatting issue, the easiest way is to convert the values to integers before printing:
val x = 1.0
println(x.toInt)
If some are integers and some are not, you need a bit more code:
def fmt[T <% math.ScalaNumericConversions](n : T) =
if(n.toInt == n) n.toInt.toString else n.toString
val a : Double = 1.0
val b : Double = 1.5
val c : Int = 1
println(fmt(a))
println(fmt(b))
println(fmt(c))
The code above should print:
1
1.5
1
The signature of the fmt method accepts any type that either is a subtype of ScalaNumericConversions or can be converted to one through implicit conversions (so we can use the toInt method).
If you are working with a Double and want to format it as a String without .0 when it's a whole number and with its decimals otherwise, then you could use String::stripSuffix:
x.toString.stripSuffix(".0")
// val x: Double = 1.34 => "1.34"
// val x: Double = 1.0 => "1"
Use type inference, rather than explicit typing.
scala> val xi = 1
xi: Int = 1
scala> val xd = 1.0
xd: Double = 1.0
scala> println(xi)
1
scala> println(xd)
1.0