-
Notifications
You must be signed in to change notification settings - Fork 361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extending Kotlin API for BigInteger and BigDecimal #49
Comments
We can head to implementing a prototype/tests now. I think it could be in a form of a pull request to https://github.com/jetbrains/kotlin |
What is the decision on the |
We consider % operator for |
|
WAT? You mean in the whole language I would thought that since |
The reason is very simple. |
Are you going to change the operator rules so that |
There cannot be |
I'm talking about code like BigInteger("2") % BigInteger("2") that currently resolves to |
That's a bug that we'll fix by this change. |
You may be right in that it's a bug, but it's still breaking source compatibility. I just wanted to make that clear. I'm neither for nor against it. |
That's a bug in stdlib, actually. '%' was accidentally bound to the wrong function in BigInteger. Our users have found it and had filed a bug. It had prompted us to reconsider the language operator, too, but it is still a separate library bug. We are trying not maintain bugs in our libraries, unless there are very good reasons to. |
Yes, it is breaking change, albeit minor, so it will not go into "1.0.x". |
@elizarov Actually, in Math it is the IMHO you should leave |
You are right, that in Pascal Java and all other modern languages don't copy Pascal, but follow the Math. They call '%' a remainder operation, because
|
I see your point. Then, it we want the name of the operator to originate from "reminder", could that be a more clear naming than See that in Java. They call it |
There is a Kotlin tradition to give short names to mathematical operators. Operator for |
On the other hand, we have I see no harm in using |
Can you, please, clarify what's confusing with |
It is that at first I have worked with Haskell some time ago, but I totally forgot it had So "confusing" in this context is when one looks at an unfamiliar Kotlin code ( |
The only thing, that |
Let's do a roundup:
|
Options suggested so far:
|
Naming things is famously the most complex problem in computer science. On one hand, there is indeed a similarity of P.S. Calling a remainder operator |
I've just noticed that BASIC uses |
I've updated the proposal to reflect on the changes introduced in Kotlin 1.1 |
I mean regular overloads, similar to |
I would love to see support for BigDecimal constants on Kotlin. You could use a dollar ($) prefix for the BigDecimal constants. This way you can write: var balance = $1_000.00 // var balance = BigDecimal("1000.00") |
You can define the following extension val:
and then write:
Seems to be much clearer. |
@elizarov Double cannot accurately represent base 10 so a BigDecimal constructor using double is unpredictable. You could try to do the same thing using a String instead of Double but "1000.00".bd is not that clear. |
@ezioamf I'm not suggesting to use BigDecimal constructor using double. I'm suggesting to use Kotlin's
It is very predictable, in the sense that |
Isn’t the toString() converting from double to string?
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Wednesday, October 18, 2017 7:50:00 PM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
@ezioamf<https://github.com/ezioamf> I'm not suggesting to use BigDecimal constructor using double. I'm suggesting to use Kotlin's toBigDecimal() extension function that is available in Kotlin 1.2 and which internally uses a string constructor. In Kotlin 1.1 you can define it like this:
val Double.bd: BigDecimal get() = BigDecimal(toString())
It is very predictable, in the sense that println(0.1.bd) prints precisely "0.1". You can try it here<https://try.kotlinlang.org/#/UserProjects/7qbn1nl4cbtaem3brjvjm2oh2f/fpb5hvh1l1ka41rkko7icadni6>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4sIliiyv73684FKOyXcMViBJfnvaks5strjXgaJpZM4J_Mc5>.
|
@ezioamf
That is why 0.1 gets converted to string "0.1", but not to "0.1000000000000000055511151231257827021181583404541015625" (which is the actual decimal value of the 0.1 double literal). |
I know how it works. The toString minimize the errors but not remove it.
Try 9_999_999_999.000001.bd
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Wednesday, October 18, 2017 8:43:15 PM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
@ezioamf<https://github.com/ezioamf> Double.toString() does convert the double to string. You can read the specification of this conversion here<https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#toString-double->. The most important part of that spec if here:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double.
That is why 0.1 gets converted to string "0.1", but not to "0.1000000000000000055511151231257827021181583404541015625" (which is the actual decimal value of the 0.1 double literal).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4h4UDeJuF9iehsjWVRYTqNXwMoblks5stsVTgaJpZM4J_Mc5>.
|
I don't need to run this code. I can count digits to see that the literal If you are into writing such long decimals, you can also declare a string extension for them:
Not as neat, but the you can do |
Yep. 16 digits are the maximum precision of double. I have been using strings to initialize BigDecimal for a long time and just wanted to not have to ;)
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Wednesday, October 18, 2017 10:26:31 PM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
I don't need to run this code. I can count digits to see that the literal 9_999_999_999.000001 is on the edge of the precision of double. Kotlin IDE should actually highlight it to avoid mistakes (non related to big-decimals at all, will bite you in any kind of numeric code). Good catch. We really need such kind of an inspection: KT-20837<https://youtrack.jetbrains.com/issue/KT-20837>
If you are into writing such long decimal, you can also declare as string extension for them:
val String.bd: BigDecimal get() = BigDecimal(this.replace("_", ""))
Not as neat, but the you can do "9_999_999_999.000001".bd to get a correct BigDecimal value. Combined with KT-20837 for safe usage of short literals that should be quite usable.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4vYgOCTj3wH7AdPlOL-k9r73LtDYks5stt2HgaJpZM4J_Mc5>.
|
Support for custom literals in Kotlin is in the future far-far away. If you look at the road that C++ took to support custom literals, you'll see that the support for |
I was not thinking on something generic as constexpr but to change the Lexer to evaluate $1.00 as BigDecimal constant the same way 1L is evaluated to long. I know that is not elegant but can solve soo many problems. Maybe on another language :(
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Wednesday, October 18, 2017 10:40:15 PM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
Support for custom literals in Kotlin is in the future far-far away. If you look at the road that C++ took to support custom literals, you'll see that the support for constexpr is the prerequisite for it. And Kotlin is still far from even having that: KT-14652<https://youtrack.jetbrains.com/issue/KT-14652>. There are more pressing problems at Kotlin's plate at the moment.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4u7Xe6Y8xRcn-jZQGBsZR_JYVjiPks5stuC_gaJpZM4J_Mc5>.
|
Kotlin does not have a built-in |
Financial, enterprise, scientific, and all software that deals with monetary values may be too niche but I still can dream ;)
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Wednesday, October 18, 2017 11:26:36 PM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
Kotlin does not have a built-in BigDecimal type. Moreover, BigDecimal is currently not even a part of Kotlin stdlib (it is available only on JVM as java.math.BigDecimal). While it might become a part of Kotlin stdlib in the future, it is still too weak of a connection to support "big decimal literals" in compiler. It has to built-in to have literals. But big decimals seem to be too niche of a feature (for a general-purpose language like Kotlin) to support them as a built-in type.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4vknhK6SU-u1WUJZhSd3znN0y8hqks5stuucgaJpZM4J_Mc5>.
|
It is niche. I've been doing all three in various proportions for 15+ years and I never had to use |
I hope you are not doing this anymore :)
https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency
On Oct 19, 2017, at 00:53, Roman Elizarov <notifications@github.com<mailto:notifications@github.com>> wrote:
It is niche. I've been doing all three in various proportions for 15+ years and I never had to use BigDecimal. I was only using it for esoteric (not from real life) sports programming problems. All enterprise finance I was doing had all its monetary amount nicely fitting into double (never needed more than 15 digits of precision) and all the science I was doing was using IEEE floating-point as its bread and butter.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4tQGnoIHktdQRGbbrPF7sV2u7rj_ks5stwADgaJpZM4J_Mc5>.
|
@ezioamf I will use it again as long as I don't need more than 15 decimal digits. Unfortunately, few universities teach future programmers on how to use floating point properly (how it works, how to avoid loss of precision, how to keep decimals decimal, etc), so most people use The fact is that you only need |
LOL. After that I will sleep. You should read the answers again ;)
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Thursday, October 19, 2017 1:03:04 AM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
@ezioamf<https://github.com/ezioamf> I will use it again as long as I don't need more than 15 decimal digits.
Unfortunately, few universities teach future programmers on how to use floating point properly (how it works, how to avoid loss of precision, how to keep decimals decimal, etc), so most people use BigDecimal whether they actually need it or not. It is a dream land for consultants. You come to a customer who complains of poor performance in their "scientific" code and without having to figure out what the code actually does you can usually speed it up multiple-fold by getting rid of big decimals ;)
The fact is that you only need BigDecimal if you need more than 15 decimal digits of precision.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4jRwzMXCQFaDb5Ib-uDZ00Kall8sks5stwI3gaJpZM4J_Mc5>.
|
That SO thread is quite old. I've been stumbling upon it from time to time and there is nothing I can add or correct there. It is funny, that the answer faithfully describes how IEEE floating point works, but gives no clue on how it was, is, will, and should be used to work with monetary amounts up to 15 decimal digits. Many people will be surprised at the number and scope of financial and scientific systems around the world, that they likely interact daily with, and that work perfectly and meet all their business requirements using only Let me quote that SO question here:
I am just coming from a totally different approach to education, education for engineers, where future engineers are taught the basic of how the tools at their disposal work in different situations, what are the tradeoff between different tools, so that in the future they know how to pick the best tool for the job at hand given the constraints and requirements they have. Let me repeat. There is nothing wrong with representing money with |
Your reasoning is like saying all programs can be bug free by just being careful.
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Thursday, October 19, 2017 1:32:11 AM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
That SO thread is quite old. I've been stumbling upon it from time to time and there is nothing I can add or correct there.
It is funny, that the answer faithfully describes how IEEE floating point works, but gives no clue on how it was, is, will, and should be used to work with monetary amounts up to 15 decimal digits. Mayne people will be surprised at the number and scope of financial and scientific systems around the world, that they likely interact daily with, and that work perfectly and meet all their business requirements using only double arithmetics.
Let me quote that SO question here:
I've always been told never to represent money with double or float types
I am just coming from a totally different approach to education, education for engineers, where future engineers are taught the basic of how the tools at their disposal work in different situations, what are the tradeoff between different tools, so that in the future they know how to pick the best tool for the job at hand given the constraints and requirements they have.
Let me repeat. There is nothing wrong with representing money with double type as long as you are sure that you don't need more that 15 significant digits. Actually, the credit here goes not to IEEE committee, but the Java/JVM authors, who had specified floating point operations in such a painstaking details, to make it actually reliable and usable. You have to be careful when you are doing arithmetics on those numbers to avoid the infamous 0.1 + 0.2 != 0.3 problem, but having the need to be careful is not the reason to avoid it altogether.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4hmI5aqdPuFh7OpC7XBoWbIKOINiks5stwkLgaJpZM4J_Mc5>.
|
It is just a tradeoff like everything else in programming. You trade simple-to-reason semantics of |
If I may interrupt this discussion, I would like to note that the initial @ezioamf's proposal was about This KEEP issue was about convenient long arithmetics calculations, and the current implementation is apparently enough for all major use cases we considered. For now stdlib contains a full operators set for For details please refer to the text of the proposal or to its earlier drafts, some of which contained more functionality than the current one. |
When dealing with monetary values the performance difference between double and BigDecimal is irrelevant when compared to correctness so there is no excuses on using double against BigDecimal.
You should not need to be careful dealing with rounding, cumulative errors specially on addition/subtraction, and epsilons when comparing values when you have a better alternative.
This code is wrong:
fun main(args: Array<String>) {
val amount = 0.1
var balance = 0.3
balance -= amount
balance -= amount
if(balance < amount) print ("not enough balance")
}
This code just works:
fun main(args: Array<String>) {
var amount = java.math.BigDecimal("0.1")
var balance = java.math.BigDecimal("0.3")
balance -= amount
balance -= amount
if(balance < amount) print ("not enough balance")
}
Get Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Roman Elizarov <notifications@github.com>
Sent: Thursday, October 19, 2017 2:06:56 AM
To: Kotlin/KEEP
Cc: Ezio Fernandes; Mention
Subject: Re: [Kotlin/KEEP] Extending Kotlin API for BigInteger and BigDecimal (#49)
It is just a tradeoff like everything else in programming. You trade simple-to-reason semantics of BigDecimal versus performance of double. Which one to choose for your financial application? The right answer is -- it depends. It don't like it, when people give some other answer.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#49 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABLt4oK4dI3HQ40faL-huXIRqBc0h7nZks5stxEwgaJpZM4J_Mc5>.
|
@ezioamf although your previous comment is correct, it is irrelevant in a discussion about a language since it is up to a programmer to choose the second sample or modify the first to a working condition. As a language, Kotlin provides you an easy way to transition from |
@voddan I don't see this as irrelevant. Languages have been created and improved to help developers to create clean, concise, elegant, and correct code. Most languages have arbitrary precision types as secondary class citizens then you see buggy implementations using float, double, long, two longs... Even very experienced developers can make this kind of mistakes. Java with a good implementation of BigDecimal make it a little better but using BigDecimal to do Math creates very verbose code. See more about it here: http://www.gavaghan.org/blog/2007/11/06/c-decimal-and-java-bigdecimal-solve-roundoff-problems/ Kotlin by having operator overload led to a clean code when dealing with BigDecimal. I just wanted something simple that is BigDecimal literals so I could have even cleaner code. I could write the same code as: fun main(args: Array) { balance -= amount if(balance < amount) print ("not enough balance") Better than just literals Kotlin show have a native decimal type backed by java.lang.BigDecimal. You may say that there is no correspondent type on CPU but this is not always the case. Generic languages such C and C++ gave support for floating point types before mathematical coprocessors or floating point instructions and for 64bit longs on 32bit CPUs to help developers. Microsoft created the decimal type on C# for the same reason. Decimal on C# do not have the problems of Double by been implemented on a base 10 floating. https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal So you can write code in C# as: decimal amount = 0.1m; if(amount < balance) ... A good and concise decimal implementation would further help the adoption of Kotlin by financial and enterprise software. |
@voddan Thanks for bringing the discussion back on-topic. Let's move a discussion on BigDecimal literals into a separate venue. For a start, here is an issue on bringing BigDecimal into Kotlin proper (into stdlib), which should precede any discussion on BigDecimal literals: KT-20912. I've also created an issue for BigDecimal literals themselves: KT-20913, so that we don't mix the too. I also wrote a short post on using floating-point for decimal arithmetics, so that we can have a separate place to discuss that, too: https://medium.com/@elizarov/floating-point-for-decimals-fc2861898455 |
I will continue the discussion on the medium post. See my comment on it. |
The declarations have been released in Kotlin 1.2, thus I'm closing the KEEP. Do not hesitate to open a YouTrack issue for any additional suggestions. |
Discussions about the Extending Kotlin API for BigInteger and BigDecimal proposal will be held here.
The text was updated successfully, but these errors were encountered: