I use scala Range.by to split an range to get an array, but it miss the last one for some special bucket num, for example 100. I am puzzled, and demo as following:
object SplitDemo extends App {
val min = 0.0
val max = 7672.142857142857
val bucketNum = 100
def splitsBucket1(min: Double, max: Double, num: Int) = (min to max by ((max - min) / num)).toArray
def splitsBucket2(min: Double, max: Double, num: Int): Array[Double] = {
val rst = Array.fill[Double](num + 1)(0)
rst(0) = min
rst(num) = max
val step = (max-min)/num
for(i <- 1 until num) rst(i) = rst(i-1)+step
rst
}
val split1 = splitsBucket1(min, max, bucketNum)
println(s"Split1 size = ${split1.size}, %s".format(split1.takeRight(4).mkString(",")))
val split2 = splitsBucket2(min, max, bucketNum)
println(s"Split2 size = ${split2.size}, %s".format(split2.takeRight(4).mkString(",")))
}
the output is following
Split1 size = 100,7365.257142857143,7441.978571428572,7518.700000000001,7595.421428571429
Split2 size = 101,7441.978571428588,7518.700000000017,7595.421428571446,7672.142857142857
When num = 100, split1 misses the last one, but split2 not(which is my expection).When num is other num, e.t. 130, split1 and split2 get the sample result.
What's the reason to casuse the difference?
It's the usual floating point inaccuracy.
Look, how the max comes out differently after dividing and multiplicating it back:
scala> 7672.142857142857 / 100 * 100
res1: Double = 7672.142857142858
And this number is larger than max, so it doesn't fit into the range:
scala> max / bucketNum * bucketNum > max
res2: Boolean = true
It's still more correct than adding the step 100 hundred times in splitsBucket2:
scala> var result = 0.0
result: Double = 0.0
scala> for (_ <- 0 until 100) result += (max - min) / bucketNum
scala> result
res4: Double = 7672.142857142875
This is larger than both max and max / bucketNum * bucketNum. You avoid this in splitBuckets2 by explicitly assigning rst(num) = max though.
You can try the following split implementation:
def splitsBucket3(min: Double, max: Double, num: Int): Array[Double] = {
val step = (max - min) / num
Array.tabulate(num + 1)(min + step * _)
}
It is guaranteed to have the correct number of elements, and has less numeric precision problems than splitsBucket2.
Related
Can anybody help me understand what's wrong with the code below?
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.reduce(_.x + _.x)
val y = points.reduce(_.y + _.y)
val len = points.length
Point(x/len, y/len)
}
I get the error when I run it:
Error:(10, 30) type mismatch;
found : Double
required: A$A145.this.Point
val x = points.reduce(_.x + _.x)
^
reduce, in this case, takes a function of type (Point, Point) => Point and returns a Point.
One way to calculate the centroid:
case class Point(x: Double, y: Double)
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.map(_.x).sum
val y = points.map(_.y).sum
val len = points.length
Point(x/len, y/len)
}
If you want to use reduce you need to reduce both x and y in a single pass like this
def centroid(points: IndexedSeq[Point]): Point = {
val p = points.reduce( (s, p) => Point(s.x + p.x, s.y + p.y) )
val len = points.length
Point(p.x/len, p.y/len)
}
If you want to compute x and y independently then use foldLeft rather than reduce like this
def centroid(points: IndexedSeq[Point]): Point = {
val x = points.foldLeft(0.0)(_ + _.x)
val y = points.foldLeft(0.0)(_ + _.y)
val len = points.length
Point(x/len, y/len)
}
This is perhaps clearer but does process the points twice so it may be marginally less efficient.
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)
Given a non-increasing list of numbers, I want to pick top 85% of values in the list. Here is how I am currently doing it.
scala> val a = Array(8.60, 6.85, 4.91, 3.45, 2.74, 2.06, 1.53, 0.35, 0.28, 0.12)
a: Array[Double] = Array(8.6, 6.85, 4.91, 3.45, 2.74, 2.06, 1.53, 0.35, 0.28, 0.12)
scala> val threshold = a.sum * 0.85
threshold: Double = 26.2565
scala> val successiveSums = a.tail.foldLeft(Array[Double](a.head)){ case (x,y) => x ++ Array(y + x.last) }
successiveSums: Array[Double] = Array(8.6, 15.45, 20.36, 23.81, 26.549999999999997, 28.609999999999996, 30.139999999999997, 30.49, 30.77, 30.89)
scala> successiveSums.takeWhile( x => x <= threshold )
res40: Array[Double] = Array(8.6, 15.45, 20.36, 23.81)
scala> val size = successiveSums.takeWhile( x => x <= threshold ).size
size: Int = 4
scala> a.take(size)
res41: Array[Double] = Array(8.6, 6.85, 4.91, 3.45)
I want improve its
performance
code-size
Any suggestions ?
On code size, consider this oneliner,
a.take( a.scanLeft(0.0)(_+_).takeWhile( _ <= a.sum * 0.85 ).size - 1 )
Here scanLeft accumulates additions.
On performance, tagging intermediate values may help not to recompute same operations, namely
val threshold = a.sum * 0.85
val size = a.scanLeft(0.0)(_+_).takeWhile( _ <= threshold ).size - 1
a.take( size )
There is some space for improvement in elm's answer:
1) You don't need to compute sum 2 times.
2) You can avoid creation of additional collection with takeWhile method and use indexWhere instead.
val sums = a.scanLeft(0.0)(_ + _)
a.take(sums.indexWhere(_ > sums.last * 0.85) - 1)
There's no library method that will do exactly what you want. Generally if you want something that performs well, you'd use a tail-recursive method both to find the sum and to find the point where the 85th percentile of the total sum is crossed. Something like
def threshold(
xs: Array[Double], thresh: Double,
i: Int = 0, sum: Double = 0
) {
val next = sum + x(i)
if (next > thresh) xs.take(i)
else threshold(xs, thresh, i+1, next)
}
Well in this case I would make a little use of mutable state. See the code below:
val a = Array(8.60, 6.85, 4.91, 3.45, 2.74, 2.06, 1.53, 0.35, 0.28, 0.12)
def f(a: Array[Double]) = {
val toGet = a.sum * 0.85
var sum = 0.0
a.takeWhile(x => {sum += x; sum <= toGet })
}
println(f(a).deep) //Array(8.6, 6.85, 4.91, 3.45)
In my opinion it's acceptable because function f does not have any side effects
Is there a function that can truncate or round a Double? At one point in my code I would like a number like: 1.23456789 to be rounded to 1.23
You can use scala.math.BigDecimal:
BigDecimal(1.23456789).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
There are a number of other rounding modes, which unfortunately aren't very well documented at present (although their Java equivalents are).
Here's another solution without BigDecimals
Truncate:
(math floor 1.23456789 * 100) / 100
Round (see rint):
(math rint 1.23456789 * 100) / 100
Or for any double n and precision p:
def truncateAt(n: Double, p: Int): Double = { val s = math pow (10, p); (math floor n * s) / s }
Similar can be done for the rounding function, this time using currying:
def roundAt(p: Int)(n: Double): Double = { val s = math pow (10, p); (math round n * s) / s }
which is more reusable, e.g. when rounding money amounts the following could be used:
def roundAt2(n: Double) = roundAt(2)(n)
Since no-one mentioned the % operator yet, here comes. It only does truncation, and you cannot rely on the return value not to have floating point inaccuracies, but sometimes it's handy:
scala> 1.23456789 - (1.23456789 % 0.01)
res4: Double = 1.23
How about :
val value = 1.4142135623730951
//3 decimal places
println((value * 1000).round / 1000.toDouble)
//4 decimal places
println((value * 10000).round / 10000.toDouble)
Edit: fixed the problem that #ryryguy pointed out. (Thanks!)
If you want it to be fast, Kaito has the right idea. math.pow is slow, though. For any standard use you're better off with a recursive function:
def trunc(x: Double, n: Int) = {
def p10(n: Int, pow: Long = 10): Long = if (n==0) pow else p10(n-1,pow*10)
if (n < 0) {
val m = p10(-n).toDouble
math.round(x/m) * m
}
else {
val m = p10(n).toDouble
math.round(x*m) / m
}
}
This is about 10x faster if you're within the range of Long (i.e 18 digits), so you can round at anywhere between 10^18 and 10^-18.
For those how are interested, here are some times for the suggested solutions...
Rounding
Java Formatter: Elapsed Time: 105
Scala Formatter: Elapsed Time: 167
BigDecimal Formatter: Elapsed Time: 27
Truncation
Scala custom Formatter: Elapsed Time: 3
Truncation is the fastest, followed by BigDecimal.
Keep in mind these test were done running norma scala execution, not using any benchmarking tools.
object TestFormatters {
val r = scala.util.Random
def textFormatter(x: Double) = new java.text.DecimalFormat("0.##").format(x)
def scalaFormatter(x: Double) = "$pi%1.2f".format(x)
def bigDecimalFormatter(x: Double) = BigDecimal(x).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
def scalaCustom(x: Double) = {
val roundBy = 2
val w = math.pow(10, roundBy)
(x * w).toLong.toDouble / w
}
def timed(f: => Unit) = {
val start = System.currentTimeMillis()
f
val end = System.currentTimeMillis()
println("Elapsed Time: " + (end - start))
}
def main(args: Array[String]): Unit = {
print("Java Formatter: ")
val iters = 10000
timed {
(0 until iters) foreach { _ =>
textFormatter(r.nextDouble())
}
}
print("Scala Formatter: ")
timed {
(0 until iters) foreach { _ =>
scalaFormatter(r.nextDouble())
}
}
print("BigDecimal Formatter: ")
timed {
(0 until iters) foreach { _ =>
bigDecimalFormatter(r.nextDouble())
}
}
print("Scala custom Formatter (truncation): ")
timed {
(0 until iters) foreach { _ =>
scalaCustom(r.nextDouble())
}
}
}
}
It's actually very easy to handle using Scala f interpolator - https://docs.scala-lang.org/overviews/core/string-interpolation.html
Suppose we want to round till 2 decimal places:
scala> val sum = 1 + 1/4D + 1/7D + 1/10D + 1/13D
sum: Double = 1.5697802197802198
scala> println(f"$sum%1.2f")
1.57
You may use implicit classes:
import scala.math._
object ExtNumber extends App {
implicit class ExtendedDouble(n: Double) {
def rounded(x: Int) = {
val w = pow(10, x)
(n * w).toLong.toDouble / w
}
}
// usage
val a = 1.23456789
println(a.rounded(2))
}
Recently, I faced similar problem and I solved it using following approach
def round(value: Either[Double, Float], places: Int) = {
if (places < 0) 0
else {
val factor = Math.pow(10, places)
value match {
case Left(d) => (Math.round(d * factor) / factor)
case Right(f) => (Math.round(f * factor) / factor)
}
}
}
def round(value: Double): Double = round(Left(value), 0)
def round(value: Double, places: Int): Double = round(Left(value), places)
def round(value: Float): Double = round(Right(value), 0)
def round(value: Float, places: Int): Double = round(Right(value), places)
I used this SO issue. I have couple of overloaded functions for both Float\Double and implicit\explicit options. Note that, you need to explicitly mention the return type in case of overloaded functions.
Those are great answers in this thread. In order to better show the difference, here is just an example. The reason I put it here b/c during my work the numbers are required to be NOT half-up :
import org.apache.spark.sql.types._
val values = List(1.2345,2.9998,3.4567,4.0099,5.1231)
val df = values.toDF
df.show()
+------+
| value|
+------+
|1.2345|
|2.9998|
|3.4567|
|4.0099|
|5.1231|
+------+
val df2 = df.withColumn("floor_val", floor(col("value"))).
withColumn("dec_val", col("value").cast(DecimalType(26,2))).
withColumn("floor2", (floor(col("value") * 100.0)/100.0).cast(DecimalType(26,2)))
df2.show()
+------+---------+-------+------+
| value|floor_val|dec_val|floor2|
+------+---------+-------+------+
|1.2345| 1| 1.23| 1.23|
|2.9998| 2| 3.00| 2.99|
|3.4567| 3| 3.46| 3.45|
|4.0099| 4| 4.01| 4.00|
|5.1231| 5| 5.12| 5.12|
+------+---------+-------+------+
floor function floors to the largest interger less than current value. DecimalType by default will enable HALF_UP mode, not just cut to precision you want. If you want to cut to a certain precision without using HALF_UP mode, you can use above solution instead ( or use scala.math.BigDecimal (where you have to explicitly define rounding modes).
I wouldn't use BigDecimal if you care about performance. BigDecimal converts numbers to string and then parses it back again:
/** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */
def decimal(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc)
I'm going to stick to math manipulations as Kaito suggested.
Since the question specified rounding for doubles specifically, this seems way simpler than dealing with big integer or excessive string or numerical operations.
"%.2f".format(0.714999999999).toDouble
A bit strange but nice. I use String and not BigDecimal
def round(x: Double)(p: Int): Double = {
var A = x.toString().split('.')
(A(0) + "." + A(1).substring(0, if (p > A(1).length()) A(1).length() else p)).toDouble
}
You can do:Math.round(<double precision value> * 100.0) / 100.0
But Math.round is fastest but it breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)).
Use Bigdecimal it is bit inefficient as it converts the values to string but more relieval:
BigDecimal(<value>).setScale(<places>, RoundingMode.HALF_UP).doubleValue()
use your preference of Rounding mode.
If you are curious and want to know more detail why this happens you can read this:
I think previous answers are:
Plain wrong: using math.floor for example doesn't work for negative values..
Unnecessary complicated.
Here is a suggestion based on #kaito's answer (i can't comment yet):
def truncateAt(x: Double, p: Int): Double = {
val s = math.pow(10, p)
(x * s).toInt / s
}
toInt will work for positive and negative values.
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