Cannot convert string to a long in scala - scala

Why can I not convert the following string into a long? i am trying to do this in scala.
var a = "153978017952566571852"
val b = a.toLong
when I try to convert it I get the NumberFormatException

Because the number exceeds the limit of Long Integer which goes from -9223372036854775808 to 9223372036854775807, with maximum of 19 digits, while your string contains 21 digits.
You can convert it to Float or Double if you don't have to be exact:
scala> val b = a.toFloat
b: Float = 1.5397802E20
scala> val b = a.toDouble
b: Double = 1.5397801795256658E20

Related

Multiply Double with BigDecimal

I have a BigDecimals that's always have 30 digits after the decimal points.
And I want to multiply them with Double and get a BigDecimal with 30 digits after decimal point.
For exemple I have:
val double = 4.0
val bd = 0.111111111111111111111111111111
def multiply(d : Double, bd : BigDecimal, scale: Int) = {
BigDecimal.valueOf(d).setScale(scale).*(bd)
}
// multiply(double,bd,30) => 0.4444444444444444000000000000000000
I expected to get 0.444444444444444444444444444444 (30 times 4 after the point)
What is wrong with my method?
Your bd isn't a BigDecimal, it's a Double:
scala> val bd = 0.111111111111111111111111111111
val bd: Double = 0.1111111111111111
It gets implicitly converted to a BigDecimal (after losing precision from Double) when you call multiply.
To create the BigDecimal, you seek, it's probably best to parse a string representation:
val bd = BigDecimal("0.111111111111111111111111111111")
// bd.scale is 30
It's also probably a good idea to explicitly set the scale again in multiply after the multiplication, as it's possible for multiplying two numbers, even with the same scale, to have greater scale than either number.
def multiply(d: Double, bd: BigDecimal, scale:Int): BigDecimal =
(BigDecimal.valueOf(d).setScale(scale) * bd).setScale(scale)
Scala's BigDecimal is similar to Java's BigDecimal.
When you multiply two BigDecimals together (using the * method on the left one), you get a new BigDecimal whose scale is the sum of the scale of its operands (inputs).
The variable bd is not a BigDecimal, so its name is misleading. It is actually a double. In order to instantiate a BigDecimal, you should use a constructor, for example: BigDecimal("0.111111111111111111111111111111").
val bd = BigDecimal("0.111111111111111111111111111111")
val double = 4.0
// There is no need to call `setScale` on `d` due to the first point noted above. Set it after multiplying:
def multiply(d : Double, bd : BigDecimal, scale: Int) =
(BigDecimal.valueOf(d) * bd).setScale(scale)
val result = multiply(double, bd, 30)
println(result)
println(result.scale)
Result:
0.444444444444444444444444444444
30

How do I format numbers as percentages in Scala?

What is the simplest/idiomatic way to format percentages in Scala?
I have the following solution but I'm wondering if a more concise way exists:
val value = 0.1456
val s1 = f"the float value is ${value}%.2f"
val s2= s"the percent value is ${java.text.NumberFormat.getPercentInstance.format(value)}"
value: Double = 0.1456
s1: String = the float value is 0.15
s2: String = the percent value is 15%
If you are looking for more of a concise method, the following works and goes along with your initial idea in your code. It is also easy to add on decimal placement without having to resort to the implicit functionality. Obviously these needs to be used a lot a better solution is with the implicit method.
val value = 0.1456
val s2 = val s2 = f"the percent value is ${value*100}%.0f%%"
s2: String = the percent value is 15%
just to give a couple of other runs as well (t show rounding down here):
val value2 = 0.1416
val s3 = val s2 = f"the percent value is ${value2*100}%.0f%%"
s3: String = the percent value is 14%
Example to show adding decimal places:
val s4 = f"the percent value is ${value2*100}%.1f%%"
s4: String = the percent value is 14.2%
You could use the "pimp my library" pattern to add the asPercentage method to Doubles.
implicit class DoubleAsPercentage(d: Double) {
def asPercentage = java.text.NumberFormat.getPercentInstance.format(d)
}
val s2 = s"the percent value is ${value.asPercentage}"
You can use the f string to format the percentage to the relevant decimal places you wish. In this example, it has 4 decimal places however if you only want to return two decimal places, then use .2f in the string below.
To return 3 decimal places, then use .3f etc etc. However if you want more decimal places than suggested; "here they are 4", you will end up with trailing zeros.
val percentage = 51.9938
scala> f"I scored $percentage%.8f%% in my exams"
res164: String = I scored 51.99380000% in my exams
scala> f"I scored $percentage%.2f%% in my exams"
res165: String = I scored 51.99% in my exams

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

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.

Avoiding Overflow

This Stackoverflow post discusses the potential problem of a numeric overflow if not appending L to a number:
Here's an example from the REPL:
scala> 100000 * 100000 // no type specified, so numbers are `int`'s
res0: Int = 1410065408
One way to avoid this problem is to use L.
scala> 100000L * 100000L
res1: Long = 10000000000
Or to specify the number's types:
scala> val x: Long = 100000
x: Long = 100000
scala> x * x
res2: Long = 10000000000
What's considered the best practice to properly specify a number's type?
You should always use L if you are using a long. Otherwise, you can still have problems:
scala> val x: Long = 10000000000
<console>:1: error: integer number too large
val x: Long = 10000000000
^
scala> val x = 10000000000L
x: Long = 10000000000
The conversion due to type ascription happens after the literal has been interpreted as Int.

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