How can I make Scala save Double to a binary file and read it back with no loss of precision?
Scala already has a good framework for saving Double to a text file, encoded as a String representation in base 10. However, doing so introduces roundoff error. The conversion of IEEE 754 64-bit floating point to decimal is imperfect and introduces slight roundoff error. A simulation that is "backed up" to disk every two hours and then reloaded from disk and resumed would not be deterministic. The simulation that was left running would differ from the one that was paused and resumed from a file. Your thoughts?
To solve this problem, I think you should use BigDecimal
Precautions
The BigDecimal(String) constructor should always be preferred over BigDecimal(Double) because using BigDecimal(double) is unpredictable due to the inability of the double to represent 0.1 as exact 0.1.
If double must be used for initializing a BigDecimal, use BigDecimal.valueOf(double), which converts the Double value to String using Double.toString(double) method
Rounding mode should be provided while setting the scale
StripTrailingZeros chops off all the trailing zeros
toString() may use scientific notation but, toPlainString() will never return exponentiation in its result
Refer to this link:
https://dzone.com/articles/never-use-float-and-double-for-monetary-calculatio
You can save decimals in binary format as-is byte-by-byte:
val fos: OutputStream = ???
val out = new DataOutputStream(fos)
out.writeDouble(1.0)
Following simpadjo 's suggestion ,
val sn:List[Double] = List(
-4.2745321334280,-0.8827640054242,
0.5781790299989,-2.5173973937094,
4.3955017758756);
val outputstm:OutputStream = new FileOutputStream( "numbers.bin" )
val dos:DataOutputStream = new DataOutputStream(outputstm)
for( k <- sn ) dos.writeDouble(k)
dos.close()
outputstm.close()
Related
I'm writing a piece of code in Scala which folds over this range:
(BigInt("0") until BigInt("1000000000000")).foldLeft(...)(...)
The code itself runs perfectly if I make the range smaller, but the program execution ends with exit code 0 without even executing any of the operations within FoldLeft.
When I try some additional examples, these are the results:
val range1 = (BigInt("0") until BigInt("1000000000000"))
println(range1(take(1)))
Result: No output, Process finished with exit code 0
val range2 (BigInt("0") until BigInt("1000"))
println(range2(take(1)))
Result: NumericRange 0 to 0, Process finished with exit code 0
As you can see, the range glitches out even if it doesn't ever evaluate the upper bound of the range. How can this happen? Numeric Ranges appear to be defined in the documentation as being valid, but as soon as they are actually used they glitch out.
Furthermore, in debug mode (IntelliJ) range1 throws an IllegalArgumentException when it is examined in-memory, because its size cannot be evaluated. When I check the documentation it seems this is correct, as the size of NumericRanges is definied by an Int.
Does this mean numeric ranges are basically impossible to use on large ranges in Scala?
TL;DR
Tried: iterating over Scala ranges using the until and to keywords, using the datatypes long and BigInt, with the size of the range larger than Int.MaxValue
Expected: able to iterate over numeric ranges
Result: program terminates unexpectedly
EDIT: Additional context, I'm having trouble with getting Scala to throw exceptions in general. I'm not sure if this is a scala problem or an intellij problem at the moment.
This is indeed a bug of scala collection library (NumericRange). Just to explain what happens, when you try to take some amount of values in a range, the API is designed to check if the amount of elements in the new range are more than Int.MaxValue, then it throws the exception. Here:
// ...
val limit = num.fromInt(Int.MaxValue)
// ...
if (num.gt(t, limit)) throw new IllegalArgumentException("More than Int.MaxValue elements.")
else t
// ...
But the same exact thing is not checked when you're actually creating new ranges, and that's unpredictable for the developers.
I state that I am new with Flutter.
I would like to do 50/2
I try with the DartPad
print((50/2).toString()); // return 25
I try the Flutter debugger build that I installed in a Pixel 4 emulator
print((50/2).toString()); // return 25.0
Why does the ".0" return?
Was I wrong to do something?
Is everything normal and is it kind of a code conversion?
How can I get it without ".0"?
ps. This is a case but I'm also talking about more complex situations where instead of doing a precise division, I could divide two variables (which maybe are not int but double) and / or do other operations. I've already evaluated things like toStringAsPrecision, it works for the single case but messes up the string if it contains true decimals.
ps2. The only solution that came to my mind is to replace the .toString with a custom extension method that eliminates superfluous zeroes (also considering the decimal point)
If you want to skip the .0 you should use truncating division a~/b. Answer is explained here : How to do Integer division in Dart?
I know I can parse from Long from String like the following
"60".toLong
or convert Long from Double like the following
60.0.toLong
or convert Long from a String of Double like the following
"60.0".toDouble.toLong
However, I can't do the following
"60.0".toLong
So my question is whether using .toDouble.toLong is a best practice, or should I use something like try ... catch ...?
Meanwhile, there is another question, when I try to convert a very large Long to Double, there maybe some precision loss, I want to know how to fix that?
"9223372036854775800.31415926535827932".toDouble.toLong
You should wrap the operation in a Try anyway, in case the string is not valid.
What you do inside the Try depends on whether "60.0" is a valid value in your application.
If it is valid, use the two-step conversion.
Try("60.0".toDouble.toLong) // => Success(60)
If it is not valid, use the one-step version.
Try("60.0".toLong) // => Failure(java.lang.NumberFormatException...)
Answer to updated question:
9223372036854775800.31415926535827932 is outside the range for a Double, so you need BigDecimal for that.
Try(BigDecimal("9223372036854775800.31415926535827932").toLong)
However you are very close to maximum value for Long, so if the numbers really are that large I suggest avoiding Long and using BigDecimal and BigInt.
Try(BigDecimal("9223372036854775800.31415926535827932").toBigInt)
Note that toLong will not fail if the BigDecimal is too large, it just gives the wrong value.
On scala my BigDecimal is 3.721443204405954385563870541379242E+54
I would like to result to 3721443204405954385563870541379246659709506697378694300
My result is:
3.114968783111033211375362915188093E+41
I would like to result to be:
311496878311103321137536291518809134027240
I do not know the scale and the result should be only show the integer part.
val multimes:(Int, Int)=>BigDecimal=(c:Int, begin:Int)=>{
if(c==1)
BigDecimal.apply(begin)
else
multimes(c-1, begin)*(c+begin-1)
}
def mulCount(c:Int):BigDecimal={
val upper=multimes(c,c+1)
val down=multimes(c,2)
upper/down
}
the number is the result of function mulCount.
The BigDecimal class has a number of nonintuitive behaviors in Scala 2.10. This will get better in 2.11, but I can't quite tell from your example whether it will fix what you want. Probably not; Scala has a default MathContext which keeps about 128 bits of information (~34 decimal digits), and I think that's what you're running into here.
If you don't have a decimal problem--and here you don't--then the easiest thing to do is just use BigInt instead. It will scale to however many digits you actually need.
If you must express this as a decimal problem, you should explicitly supply a MathContext that has enough digits:
if (c==1) BigDecimal.apply(begin, new java.math.MathContext(60))
and that MathContext will, if always used on the left-hand side of operations, propagate through to your result.
It sounds as though you're mostly concerned about the appearance of the number, and don't want to see it in scientific notation with the exponent.
This is default behaviour for just printing a BigDecimal and can't be overridden. But you can explicitly convert it to a String before printing.
This should do the trick:
val bd: BigDecimal = ...
println(bd.bigDecimal.toPlainString)
That said... Why not just use BigInt?
Float values are getting changed after parsing with JSONKit. The problem occurs after calling objectFromJSONString or mutableObjectFromJSONString.
The JSON response is fine before this method is triggered in JSONKit.m:
static id _NSStringObjectFromJSONString(NSString *jsonString, JKParseOptionFlags parseOptionFlags, NSError **error, BOOL mutableCollection)
Original response:
"value":"1002.65"
Response after calling objectFromJSONString:
"value":"1002.6500000001" or sometimes "value":"1002.649999999 "
Thanks.
This is not an issue.
The value 1002.65 can not be represented exactly using a IEEE 754 floating point number.
Floating-point numbers are converted to their decimal representation using the printf format conversion specifier %.17g.
From the Docs:
The C double primitive type, or IEEE 754 Double 64-bit floating-point,
is used to represent floating-point JSON Number values. JSON that
contains floating-point Number values that can not be represented as a
double (i.e., due to over or underflow) will fail to parse and
optionally return a NSError object. The function strtod() is used to
perform the conversion. Note that the JSON standard does not allow for
infinities or NaN (Not a Number). The conversion and manipulation of
floating-point values is non-trivial. Unfortunately, RFC 4627 is
silent on how such details should be handled. You should not depend on
or expect that when a floating-point value is round tripped that it
will have the same textual representation or even compare equal. This
is true even when JSONKit is used as both the parser and creator of
the JSON, let alone when transferring JSON between different systems
and implementations.
Source: See this thread https://github.com/johnezang/JSONKit/issues/110
Solution: You can specify a precision, while converting float to string for output. NSNumberFormatter will be a better choice or use some printf solutions like in the previous answer.
use float fixed point representation like,
NSLog(#"value = %.2f",floatvalue);
now it will show value = 1002.65