How to avoid round off and scientific notation in double in scala? - scala

Given:
scala> val s =99999999999999947.89
s: Double = 9.9999999999999952E16
scala> f"$s%.2f"
res15: String = 99999999999999952.00
i want output should be = 99999999999999947.89
how to avoid round off and scientific notation both.

The Double datatype doesn't support the precision you're after. The closest number 99999999999999952 is the number closest to 99999999999999947.89 that can be represented as a Double.
That's not just the case for very big numbers. Double values can soon start to drift. You can see this for example in that (0.2 + 0.2 + 0.2) != 0.6
Use a BigDecimal instead.

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

Scala BigDecimal - loss of precision

I need to do some precision calcs with Big Numbers and I have been trying with Scala BigDecimal but I have noted loss of precision.
As an example:
2^63 == 9223372036854775808
2^64 == 18446744073709551616
However when I do
println(BigDecimal.decimal(scala.math.pow(2, 63)).toBigIntExact())
println(BigDecimal.decimal(scala.math.pow(2, 64)).toBigIntExact())
I get
9223372036854776000 != 9223372036854775808
18446744073709552000 != 18446744073709551616
I don't know if I can get the exact BigInt.
Maybe I have to take other approach.
Could anyone help me to fix this issue?
# scala.math.pow(2, 63)
res0: Double = 9.223372036854776E18
You get Double on math.pow, and then you pass the result to BigDecimal - it means that you lost precision even before you started using Big* classes.
If you put numbers into BigDecimal when they are still small and haven't yet lost precision (and if you use the constructors correctly) then you'll get the expected result:
# BigDecimal(2).pow(63).toBigInt
res4: BigInt = 9223372036854775808
# BigDecimal(2).pow(64).toBigInt
res5: BigInt = 18446744073709551616
# BigDecimal(2).pow(63).toBigIntExact
res6: Option[BigInt] = Some(9223372036854775808)
# BigDecimal(2).pow(64).toBigIntExact
res7: Option[BigInt] = Some(18446744073709551616)

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

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.

How to perform calculation given multiple types of numbers?

I have some numbers list that I go through it, and doing a simple calculation to for two numbers:
I have numberA and numberB, and the calculation im doing is:
val res = (numberA/numberB) * 100
now, I dont know what type is the number, but I know it could be float (with 2 nums after the dot) or integer...
so I want to know what is the syntax in scala to calculate it?
currently I have:
val num1 = (vatReclaimed.toInt/vatPaid.toInt) * 100
but its obviously dont work, and I cannot really use toInt i guess since I dont know the type...
whats important to me that the res will hold the right answer, so if its 2.3 * 4 the res will hold 9.2
thanksss!
When you do not know the type only, that is a number, you probably have to work with Numeric. With numeric you can convert any numeric value to Double, Float, Int or Long. For precision I would recommend Double:
def calc[A : Numeric, B : Numeric](a: A, b: B): Double = (a.toDouble / b.toDouble) * 100