groostav
03/27/2023, 7:25 PMval firstDbl: Double = 0.1
val firstStr: String = "0.1"
val firstBigStr = BigDecimal("0.1")
val firstBigDbl = BigDecimal(0.1)
has some funny equality implications:
firstDbl == firstStr.toDouble() //true
firstBigStr == firstBigDbl //false
firstBigStr.toDouble() == firstBigDbl.toDouble() // false, 0.1 != 0.0...555
firstBigDb.toString() // 0.1000000000000000055511151231257827021181583404541015625
Can somebody help me understand where this error came from? Should i be calling a different BigDecimal constructor?ephemient
03/27/2023, 7:29 PM0.1
in codegroostav
03/27/2023, 7:29 PMDouble.toString()
knew how to get it back?ephemient
03/27/2023, 7:30 PM.toString()
finds the shortest string representation that produces the same value, not the exact representation0.1000000000000000055511151231257827021181583404541015625 == 0.1
groostav
03/27/2023, 7:30 PM0x3FB999999999999A
ephemient
03/27/2023, 7:31 PMtoString()
produces the latter, BigDecimal
captures all of the formergroostav
03/27/2023, 7:37 PMdouble
fields to store some input from a user. Its pretty straight forward. I was aware that the first time you do an operation on that value you've incurred a loss, but I had thought that any value that was denotable within the precision limits of IEEE 754 was, how should I say, recoverable as its denotation within those bounds.
IE, if i wrote 0.1
in a text field (or indeed in intelliJ as a constant), the I would get the bits 0x3FB999999999999A
, and, like an ASCII coding of A
to 0x41
, i could convert back and forth between them as I saw fit.ephemient
03/27/2023, 7:38 PM0.1
is not actually 0.1
as you think of it, as that cannot be exactly representedgroostav
03/27/2023, 7:39 PMratio
primative in kotlin, i wonder if thats already an issueephemient
03/27/2023, 7:41 PMgroostav
03/27/2023, 7:42 PM0.1r
, but im digressingval myDouble = doubleParsedFromDenotableUserText(text)
how safe is it to write val bigDecimal = BigDecimal(myDouble.toString())
,
I guess my question is how much of a perfect dual operation is text.toDouble()
and double.toString()
? when will the two not produce a result that agrees?ephemient
03/27/2023, 7:44 PMdouble.toString().toDouble()
is supposed to round-trip (for finite values, on JVM - not JS), but string.toDouble().toString()
is not, as there are many possible string representations for the same floating-point valuegroostav
03/27/2023, 7:48 PM0.1
?ephemient
03/27/2023, 7:49 PMgroostav
03/27/2023, 7:50 PM0.1 == 0.100000000000000005 && 0.1 == 0.0.100000000000000005999
is trueephemient
03/27/2023, 7:50 PM"0.099999999999999999".toDouble() == "0.1".toDouble()
groostav
03/27/2023, 7:50 PMephemient
03/27/2023, 7:51 PMDouble
which will .toString()
to "0.1"
?groostav
03/27/2023, 7:51 PMephemient
03/27/2023, 7:51 PMgroostav
03/27/2023, 7:58 PMdouble
, and back again, losslessly?double
value (IE, a double value we knew was parsed from a Denotable), we could get that denotable representation backephemient
03/27/2023, 8:01 PMgroostav
03/27/2023, 8:02 PMephemient
03/27/2023, 8:04 PMgroostav
03/27/2023, 8:04 PMephemient
03/27/2023, 8:07 PMDouble.toString
docs): 1.0E23.toString() == "9.999999999999999E22"
groostav
03/27/2023, 8:07 PMBigDecimal
on my model istead of a double
, but im trying to understand the scope of the failures I can see with the use of double
. It seems like, perhalps a reasonable intermediate fix is to do a double.toString().toDouble
as a kind of validation on user input, and then... do something if input != input.toDouble().toString()
ephemient
03/27/2023, 8:12 PM0.0 == -0.0
(0.0).toString() != (-0.0).toString()
groostav
03/27/2023, 8:12 PM-0.0
is denotable differently than 0.0
, so the fact that it gives you different representation doesnt violate the rule-0.0.toString() == "-0.0"
its fineephemient
03/27/2023, 8:16 PMrequire(input == input.toDouble().toString())
may force you to enter certain values differently on different JVMs - aside from the bug above, the representation is supposed to be minimal but not necessarily uniquegroostav
03/27/2023, 8:21 PMtoDouble.toString()
where appropriateDoubleConverter
or DecimalFormat
thats a bit more strict about thisephemient
03/27/2023, 8:25 PM