I'm unit testing and I can't compute the factorial of 100. I read that using BigInt would help, but I'm not sure what I'm doing wrong, because it still doesn't work.
Here is my function.
package Factorial{
class factorial
{
def recursive_factorial(number:BigInt) : BigInt =
{
if (number == 0)
return 1
number * recursive_factorial (number - 1)
}
}
}
If I call the function with recursive_factorial(100).. I get an error that the number is too large for an int
The code you posted works fine. The problem is the code you use to test your code (which you posted in a comment to another answer):
assertResult(93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000) {
factorial.recursive_factorial(100)
}
The problem is that integer literals have type Int and the number 93326... is obviously too large to fit into an int, so you can't use an integer literal to represent it.
One way to create a BigInt of a large number is to write it as a string and convert that to a BigInt. So this will work fine:
assertResult(BigInt("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000")) {
factorial.recursive_factorial(100)
}
first of all, your function has the problem of causing a stackoverflow when number is too large. You should write it tail-recursively:
#annotation.tailrec
def recursive_factorial(number: BigInt, result: BigInt = 1): BigInt = {
if (number == 0)
result
else
recursive_factorial(number -1, result * number)
}
otherwise, your code example works perfectly for me and I don't know what your problem is. Probably, you try to write the result of this function (which is a BigInt) into an Int at some point which triggers the error.
The function is just fine. Only limitation is the data type BigInt/BigInteger does not support arbitrary-precision point integer operation which can be done by BigDecimal. It works like a wrapper to BigInt. That's why instead of showing the big number it shows 9.332621544394415268169923885626674E+157. There is a discussion on which data type to use and when in the link below.
Performace of BigDecimal vs. BigInteger and BigDecimal
Related
New to Scala and am trying to come up with a library in Scala to check if the double value being passed is of a certain precision and scale. What I noticed was that if the value being passed is 1.00001 then I get the value as that in my called function, but if the value being passed is 0.00001 then I get the value as 1.0E-5, Is there any way to preserve the number in Scala?
def checkPrecisionAndScaleFormat(precision: Int, scale: Int)(valueToCheck: Double): Boolean = {
val value = BigDecimal(valueToCheck)
value.precision <= precision && value.scale <= scale
}
What I noticed was that if the value being passed is 1.00001 then I get the value as that in my called function, but if the value being passed is 0.00001 then I get the value as 1.0E-5
From your phrasing, it seems like you see 1.00001 and 1.0E-5 when debugging (either by printing or in the debugger). It's important to understand that
this doesn't correspond to any internal difference, it's just how Double.toString is defined in Java.
when you do something like val x = 1.00001, the value isn't exactly 1.00001 but the closest number representable as a Double: 1.000010000000000065512040237081237137317657470703125. The easiest way to see the exact value is actually looking at BigDecimal.exact(valueToCheck).
The only way to preserve the number is not to work with Double to begin with. If it's passed as a string, create the BigDecimal from the string. If it's the result of some calculations as a double, consider doing them on BigDecimals instead. But string representation of a Double simply doesn't carry the information you want.
I am processing a large number of records (CDRS) that are essentially (who, where, how much), to save space I use a lookup to map the strings into integer and aggregate the traffic on a map of maps (who maps to a map (where maps how much)
type CDR = (String, String, Int)
type Lookup = scala.collection.mutable.HashMap[String, (Int, Float)]
type Traffic = scala.collection.mutable.HashMap[Int,scala.collection.mutable.HashMap[Int,Int]]enter code here
I have found a strange behavior, when I build the lookup tables in advance the code runs as expected, however when I start processing and build the maps on the fly it slows down as it processes the records.
I use the same function to build the lookup tables for this comparison. I essentially check if the code for the lookup is there, if not i create a new entry (it is a mutable map), like this:
def index(id: String, map: Lookup, reverse: Reverse): Int = {
if (map.contains(id)) {
map(id)._1
} else {
val number = if (map.keys.size == 0) 0 else reverse.keys.max + 1
reverse += ( number -> id)
map += (id -> (number, 0.toFloat))
number
}
}
Am I missing something here?
EDIT----> I can no longer reproduce the slowdown. I will assume I was either too tired or dumber than usual. Running time now seems to be same as I expected to be.
What is mapCellRvs? Default scala Map's .size (and .keys.size, which is the same thing) simply counts all elements by scanning them linearly.
Try replacing mapCellRvs.keys.size == 0 with mapCellRvs.isEmpty ...
Also, reverse.keys.max is linear as well. You may want to just remember the max somewhere separately, rather than compute it every time.
def factorial(n : Int) : Int = {
if(n==1)
1
else
n * factorial(n-1)
}
println(factorial(500000))
While I am passing large value its throwing stackoverflow exception Can we fix it?
The question seems theoretical, because factorial of 500000 is really a huge number. The result is so huge it is not representable by IEEE Double, and I doubt there is any practical reason why to compute it.
Some math calculators (like SpeedCrunch) let you compute factorial using the gamma function, probably using some approximation for large numbers. The SpeedCrunch result of gamma(500000 + 1)is 1.02280158465190236533 * 10 2632341.
However, if you insist on doing it, this is how it can be done:
Implement factorial using tail recursion instead. See Tail Recursion in Scala: A Simple Example or http://alvinalexander.com/scala/scala-recursion-examples-recursive-programming
Note: you will still get integer arithmetics overflow for large inputs, and the result will be wrong for them. The largest input for a 32b signed integer for which the result will still fit in a 32b signed result is 12 (cf. Factorial does not work for all values)
You can avoid this by using Double to compute the result (you will get approximate result only for large numbers, and Infinity for 500000) or by using BigInt - the calculation will work for all values, but it will get slower.
Following code should produce the correct result, but it might take very long, and the result will be very long - you might perhaps even get out of memory errors. I tried computing factorial of 50000 with it and it took several seconds, and the resulting number was several pages long.
def factorial(n: Long): BigInt = {
#tailrec
def factorialAccumulator(acc: BigInt, n: Long): BigInt = {
if (n == 0) acc
else factorialAccumulator(n*acc, n-1)
}
factorialAccumulator(1, n)
}
// Purpose: Determine attendance based on ticket-price
// Example: attendance(4.90) == 135
def attendance: Double => Int = {
(ticket_price: Double) => {
120 + math.ceil(150 * (5.00 - ticket_price)).toInt
}
} //> attendance: => Double => Int
attendance(4.90) //> res0: Int = 135
assert(attendance(4.90) == 135)
Basically the assert was blowing up and attendance was returning 134 instead of 135. So I threw math.ceil at it and it worked. But I was just wondering if that's the best/proper/idiomatic way to do it.
For those who wonder where this code came from: attendance code
When working with money, you should not use float/double types. I know these ways:
Use integer numbers (i.e. Short, Int, Long etc.) with the smallest possible values (e.g. cents, satoshis, ...). This might be enhanced by value classes in Scala.
Use precise arithmetics like BigDecimal.
Use fixed point arithmetics with arbitrary precision. (This is basically the same with a).)
Note that you should be aware of integer overflows when working with money.
I have a csv file where amount and quantity fields are present in each detail record except header and trailer record. Trailer record has a total charge values which is the total sum of quantity multiplied by amount field in detail records . I need to check whether the trailer total charge value is equal to my calculated value of amount and quantity fields. I am using the double data type for all these calculations. When i browsed i am able to understand from the below web link that it might create an issue using double datatype while comparison with decimal points. It's suggesting to using BigDecimal
http://epramono.blogspot.com/2005/01/double-vs-bigdecimal.html
Will i get issues if i use double data type. How can i do the calculations using BigDecimal. Also i am not sure how many digits i will get after decimal points in csv file. Also amount can have a positive or negative value.
In csv file
H,ABC.....
"D",....,"1","12.23"
"D",.....,"3","-13.334"
"D",......,"2","12"
T,csd,123,12.345
------------------------------ While Validation i am having the below code --------------------
double detChargeCount =0;
//From csv file i am reading trailer records charge value
String totChargeValue = items[3].replaceAll("\"","").trim();
if (null != totChargeValue && !totChargeValue.equals("")) {
detChargeCount = new Double(totChargeValue).doubleValue();
if(detChargeCount==calChargeCount)
validflag=true;
-----------------------While reading CSV File i am having the below code
if (null != chargeQuan && !chargeQuan.equals("")) {
tmpChargeQuan=Long(chargeQuan).longValue();
}
if (null != chargeAmount && !chargeAmount.equals("")) {
tmpChargeAmt=new Double(chargeAmount).doubleValue();
calChargeCount=calChargeCount+(tmpChargeQuan*tmpChargeAmt);
}
I had declared the variables tmpChargeQuan, tmpChargeAmt, calChargeCount as double
Especially for anything with financial data, but in general for everything dealing with human readable numbers, BigDecimal is what you want to use instead of double, just as that source says.
The documentation on BigDecimal is pretty straight-forward, and should provide everything you need.
It has a int, double, and string constructors, so you can simply have:
BigDecimal detChargeCount = new BigDecimal(0);
...
detChargeCount = new BigDecimal(totChargeValue);
The operators are implemented as functions, so you'd have to do things like
tmpChargeQuan.multiply(tmpChargeAmt)
instead of simply tmpChargeQun * tmpChargeAmt, but that shouldn't be a big deal.
but they're all defined with all the overloads you could need as well.
It is very possible that you will have issues with doubles, by which I mean the precomputed value and the newly computed value may differ by .000001 or less.
If you don't know how the value you are comparing to was computed, I think the best solution is to define "equal" as having a difference of less than epsilon, where epsilon is a very small number such as .0001.
I.e. rather than using the test A == B, use abs(A - B) < .0001.