digitalmars.D - Money type
- Vitaly Livshic (5/5) Jan 01 2020 Good day.
- Steven Schveighoffer (9/16) Jan 01 2020 I generally used a fixed-point type. Recently, I was going to use a
- JN (4/9) Jan 01 2020 There's a BigInt type in the standard library which might work -
- Vitaly Livshic (6/6) Jan 01 2020 Thanks Steve, JN.
- IGotD- (10/16) Jan 01 2020 That's probably because there is no standard how to deal with
- Steven Schveighoffer (9/26) Jan 01 2020 Well, that is just odd, as you then need 2 number systems, one with base...
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/10) Jan 01 2020 You don't need fixed point, just store cents in 64 bit floating
- Steven Schveighoffer (5/14) Jan 01 2020 It is stored that way. Stored as a long. Just nicer to deal with
- Steven Schveighoffer (10/24) Jan 03 2020 oops, totally misread the floating point part, I thought you said 64 bit...
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (25/32) Jan 03 2020 I actually use base10 on the server, out of convenience and easy
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (12/12) Jan 03 2020 And please forget the idea that fixed point is exact, it most
- Steven Schveighoffer (28/47) Jan 03 2020 Exactness according to the terms of what is agreed upon for discrete
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (15/21) Jan 03 2020 Yes, although in Norway you have to give prices including VAT to
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/8) Jan 04 2020 Hah! Another fixed point mistake!! It should have been:
- IGotD- (11/21) Jan 01 2020 Using floating point is not recommended. For some fractional
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (7/17) Jan 01 2020 No, not if you store as cents. You get the exact same values as
- Basile B. (4/22) Jan 02 2020 Yyou're all silly guys. Don't use floating point for currency,
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (4/6) Jan 02 2020 Drop the adhominem.
- Russel Winder (22/26) Jan 02 2020 On Thu, 2020-01-02 at 14:34 +0000, Ola Fosheim Gr=C3=B8stad via Digitalm...
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (25/38) Jan 02 2020 Oh, I am not arguing that banking institutions should use base 2
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/8) Jan 02 2020 Typo: 90 trillion USD, so 9000 trillion cents.
- bauss (8/10) Jan 02 2020 Disagree with that.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/11) Jan 02 2020 As I've pointed out double can represent anything you can
- bachmeier (6/20) Jan 02 2020 I'll just throw out that Lua has no integer type:
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (19/21) Jan 02 2020 Scripting languages try to keep things simple, so having only one
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (11/16) Jan 02 2020 So easy to make mistakes with fixed point, should've been
- Guillaume Piolat (6/11) Jan 02 2020 The devil goes even further if you want to account for negative
- lithium iodate (3/7) Jan 02 2020 Lua 5.3 (released five years ago) has got integers. The text you
- bachmeier (4/13) Jan 02 2020 Okay, I'm not a Lua expert, obviously. The point still stands
- JN (2/5) Jan 02 2020 *cough* *cough* JavaScript *cough*
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (2/7) Jan 02 2020 JavaScript has 32 bit integers as an implict type though.
- H. S. Teoh (11/15) Jan 02 2020 AFAIK, the crux of the problem with using binary floating point types
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (14/20) Jan 02 2020 You can set the rounding mode. Round to even is the common
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (8/9) Jan 02 2020 Whoops, too quick, that won't work.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (10/14) Jan 02 2020 For those interested there work done on a standard for doing
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (15/19) Jan 02 2020 For the curious, on some FPUs you can test if the computations
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (14/16) Jan 03 2020 x = 3.0*value+50.0 … ;-)
- bauss (4/7) Jan 02 2020 You are right about this and the reason is that otherwise large
- bachmeier (8/15) Jan 01 2020 https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-...
- bauss (4/9) Jan 01 2020 You can use this package:
- Rumbu (7/12) Jan 04 2020 Here you have a full IEE754-2008 compliant implementation of
Good day. I came from Java world, where 'double' type inadequate for money calculation. BigDecimal serves for it. This is ugly type, but gives precise results. Which type I must use for money in D?
Jan 01 2020
On 1/1/20 10:41 AM, Vitaly Livshic wrote:Good day. I came from Java world, where 'double' type inadequate for money calculation. BigDecimal serves for it. This is ugly type, but gives precise results. Which type I must use for money in D?I generally used a fixed-point type. Recently, I was going to use a project in code.dlang.org called fixed, but the string-based constructor uses a conversion to double first, negating the precision of a fixed point type. Another developer is making a new fixed point type here: https://github.com/m3m0ry/fixedpoint But it's not completely ready yet. -Steve
Jan 01 2020
On Wednesday, 1 January 2020 at 15:41:32 UTC, Vitaly Livshic wrote:Good day. I came from Java world, where 'double' type inadequate for money calculation. BigDecimal serves for it. This is ugly type, but gives precise results. Which type I must use for money in D?There's a BigInt type in the standard library which might work - https://dlang.org/phobos/std_bigint.html
Jan 01 2020
Thanks Steve, JN. JN, BigInt is big integer. It cannot works with fractional numbers. It is sadly, that wide-spread languages have no convinient money type. This is abnormal. Hope, D will have fixed point type either as built-in type or library.
Jan 01 2020
On Wednesday, 1 January 2020 at 18:16:01 UTC, Vitaly Livshic wrote:Thanks Steve, JN. JN, BigInt is big integer. It cannot works with fractional numbers. It is sadly, that wide-spread languages have no convinient money type. This is abnormal. Hope, D will have fixed point type either as built-in type or library.That's probably because there is no standard how to deal with currencies. Think about Shillings and it goes 12 pence on one Shilling, weird stuff like that. Also why use fixed point? Why not have currency * 100 as there goes hundred cents in one base currency, for many currencies. To convert it back you just divide by 100 and you get the value and the cent value. Well * 100 is fixed point, but in computer land fixed point usually means some scale factor of the power of 2.
Jan 01 2020
On 1/1/20 1:46 PM, IGotD- wrote:On Wednesday, 1 January 2020 at 18:16:01 UTC, Vitaly Livshic wrote:Well, that is just odd, as you then need 2 number systems, one with base 12, and one with base 10. Probably best to split that into a byte for pence and some other integer for the shillings.Thanks Steve, JN. JN, BigInt is big integer. It cannot works with fractional numbers. It is sadly, that wide-spread languages have no convinient money type. This is abnormal. Hope, D will have fixed point type either as built-in type or library.That's probably because there is no standard how to deal with currencies. Think about Shillings and it goes 12 pence on one Shilling, weird stuff like that.Also why use fixed point? Why not have currency * 100 as there goes hundred cents in one base currency, for many currencies. To convert it back you just divide by 100 and you get the value and the cent value. Well * 100 is fixed point, but in computer land fixed point usually means some scale factor of the power of 2.That is what I use. Fixed point with a factor of power of 10. In other words, a fixed point number with 2 decimal places would be sufficient for such currency. When doing math on such types, you just need to deal with the underlying numbers, and it works fine. -Steve
Jan 01 2020
On Wednesday, 1 January 2020 at 19:01:36 UTC, Steven Schveighoffer wrote:That is what I use. Fixed point with a factor of power of 10. In other words, a fixed point number with 2 decimal places would be sufficient for such currency. When doing math on such types, you just need to deal with the underlying numbers, and it works fine.You don't need fixed point, just store cents in 64 bit floating point and you get at least the same accuracy as a 53 bit integer fixed point.
Jan 01 2020
On 1/1/20 3:20 PM, Ola Fosheim Grøstad wrote:On Wednesday, 1 January 2020 at 19:01:36 UTC, Steven Schveighoffer wrote:It is stored that way. Stored as a long. Just nicer to deal with printing and such. And instead of having to remember the factor, it's stored with the type. -SteveThat is what I use. Fixed point with a factor of power of 10. In other words, a fixed point number with 2 decimal places would be sufficient for such currency. When doing math on such types, you just need to deal with the underlying numbers, and it works fine.You don't need fixed point, just store cents in 64 bit floating point and you get at least the same accuracy as a 53 bit integer fixed point.
Jan 01 2020
On 1/1/20 4:06 PM, Steven Schveighoffer wrote:On 1/1/20 3:20 PM, Ola Fosheim Grøstad wrote:oops, totally misread the floating point part, I thought you said 64 bit integer. It's not a *terrible* idea, but as you accumulate more errors, they will add up. In money transactions, most of the time you have a fixed resolution, and everything is rounded at every transaction. So floating point is not necessary. I'd much rather do integer. I like the exactness, and with something like checkedInt, you shouldn't have overflow problems. -SteveOn Wednesday, 1 January 2020 at 19:01:36 UTC, Steven Schveighoffer wrote:It is stored that way. Stored as a long. Just nicer to deal with printing and such. And instead of having to remember the factor, it's stored with the type.That is what I use. Fixed point with a factor of power of 10. In other words, a fixed point number with 2 decimal places would be sufficient for such currency. When doing math on such types, you just need to deal with the underlying numbers, and it works fine.You don't need fixed point, just store cents in 64 bit floating point and you get at least the same accuracy as a 53 bit integer fixed point.
Jan 03 2020
On Friday, 3 January 2020 at 14:49:34 UTC, Steven Schveighoffer wrote:It's not a *terrible* idea, but as you accumulate more errors, they will add up.I actually use base10 on the server, out of convenience and easy maintenance, but my point is that you don't have to as long as you understand what is going on under the hood. You won't get more than a cent error and very rarely, even when you don't set the rounding mode if you think about how floating point works. And one cannot set the rounding mode in JavaScript, so that is what you have to deal with. But it depends on what you do. Nobody are going to complain that they get one cent less on the invoice than in the "web shop pricing estimate".In money transactions, most of the time you have a fixed resolution, and everything is rounded at every transaction. So floating point is not necessary.Ok, so there you have a use case. If you only add then it is no problem, but if you do more complex calculations and more complex rounding then it becomes tedious and error prone real fast. When you add various layers of rebates and sales tax and what not it can get tricky to be certain that you will stay within a fixed bit width. If the owner of the system is ok with giving a little more rebate (like a cent) then fixed point does not look like a good solution.I'd much rather do integer. I like the exactness, and with something like checkedInt, you shouldn't have overflow problems.Well, but how do you know that you have enough bits and how do you account for an unknown number of digits at compile time if the end user can type in several rebate multipliers? If you get an exception you still have a problem...? In the general case you basically need to use big-int, and then you might as well do base 10, IMHO.
Jan 03 2020
And please forget the idea that fixed point is exact, it most certainly is not! :-) Let me give an example: Assume that you have 21% VAT and prices are given including tax, then in order to find the price without VAT you have to calculate price/1.21, but in fixed point that becomes price*100/121 which will have a remainder. So then you also have to deal with the remainder, so not exact at all. If you want the price without VAT, rounded you'll have to do: (price * 200 / 242 + 1) / 2 If you want to deal with the price without VAT with no rounding, you will have to emulate rational numbers...
Jan 03 2020
On 1/3/20 12:14 PM, Ola Fosheim Grøstad wrote:And please forget the idea that fixed point is exact, it most certainly is not! :-)Exactness according to the terms of what is agreed upon for discrete units. Not according to some IEEE standard where the discreteness varies based on value. If you want complete exactness, rational numbers are what you need, and I do use those in other places.Let me give an example: Assume that you have 21% VAT and prices are given including tax, then in order to find the price without VAT you have to calculate price/1.21, but in fixed point that becomes price*100/121 which will have a remainder. So then you also have to deal with the remainder, so not exact at all. If you want the price without VAT, rounded you'll have to do: (price * 200 / 242 + 1) / 2 If you want to deal with the price without VAT with no rounding, you will have to emulate rational numbers...You are starting from an inexact figure to begin with (almost certainly it has been rounded). Of course your figures will not be exact, in any number system. If tax is added on top of the total taxable cost, then a per-item cost is going to be inexact anyway (some will have one extra cent added due to the rounding). Generally you are only dealing with transaction amounts in full cents, unless there is some electronic form of payment, and in that case, you have a limit as to what you are dealing with. I'll take inexactness based on rounding, but consistent and agreed upon rules, over inexactness of actual value, any day. I'll give you an example, you go to the store and an item is on sale for 3 for $5.00. The cost for the first item is $1.67, the cost for the second item is $1.67, the cost for the third is $1.66. Total is $5. But if you buy one item, it's $1.67. I can understand the rules without any issue. I can't tell you what happens when you multiply 5.0/3.0 * 3.0 (or even 500.0/3.0 * 3.0). Most likely it's fine, but I can't tell you that for sure it is going to be fine. You can create systems that have rules for how to deal with imprecision, but you need to base it on types that are easy to predict and don't require IEEE experts to understand. -Steve
Jan 03 2020
On Friday, 3 January 2020 at 17:45:44 UTC, Steven Schveighoffer wrote:If tax is added on top of the total taxable cost, then a per-item cost is going to be inexact anyway (some will have one extra cent added due to the rounding).Yes, although in Norway you have to give prices including VAT to consumers, but not to businesses where excluded VAT is the norm. So to get nice looking figures like "9.90" to consumers or to businesses you can either set the price including/excluding VAT and calculate the other unit doing multiplication/division. (The "law" is that the VAT is added, but that is only in book keeping).You can create systems that have rules for how to deal with imprecision, but you need to base it on types that are easy to predict and don't require IEEE experts to understand.In that case you have to rule out fixed point and you'll have to settle for a large base 10 type. I think that is going a bit far. In my book it all depends on the situation, and the programmer is obviously part of that, but so is the platform (e.g. javascript), laws and regulations, whether it is for estimates or invoices, if it is used for accounting or sales pitch, etc etc.
Jan 03 2020
On Friday, 3 January 2020 at 17:14:06 UTC, Ola Fosheim Grøstad wrote:If you want the price without VAT, rounded you'll have to do: (price * 200 / 242 + 1) / 2Hah! Another fixed point mistake!! It should have been: (price * 200 / 121 + 1) / 2 This is what makes fixed point a chore, it is hard to read and tricky to maintain, even when it was easy to write...
Jan 04 2020
On Wednesday, 1 January 2020 at 20:20:14 UTC, Ola Fosheim Grøstad wrote:On Wednesday, 1 January 2020 at 19:01:36 UTC, Steven Schveighoffer wrote:Using floating point is not recommended. For some fractional number it is actually impossible to store the value as a rational binary number. For example 8.90 would be stored as 8.89999999999+ (in reality this is binary values so just think of my example in an equivalent binary value case). This would lead to some rounding errors, especially when chaining several operations. You should go for a representation that always calculates the currency exact, down to the cent or whatever it is. Not doing so you might even be breaking the law for some appliances.That is what I use. Fixed point with a factor of power of 10. In other words, a fixed point number with 2 decimal places would be sufficient for such currency. When doing math on such types, you just need to deal with the underlying numbers, and it works fine.You don't need fixed point, just store cents in 64 bit floating point and you get at least the same accuracy as a 53 bit integer fixed point.
Jan 01 2020
On Wednesday, 1 January 2020 at 22:04:00 UTC, IGotD- wrote:Using floating point is not recommended. For some fractional number it is actually impossible to store the value as a rational binary number. For example 8.90 would be stored as 8.89999999999+ (in reality this is binary values so just think of my example in an equivalent binary value case). This would lead to some rounding errors, especially when chaining several operations.No, not if you store as cents. You get the exact same values as with 53 bits integers with IEEE754. You have to pay atttentition to rounding mode, even-odd is common.You should go for a representation that always calculates the currency exact, down to the cent or whatever it is. Not doing so you might even be breaking the law for some appliances.Double will do that fine. As I said, same as integer. If you need half-cents, just multiply with 200 instead of 100. Or you could use millis (multiply by 1000).
Jan 01 2020
On Wednesday, 1 January 2020 at 22:26:30 UTC, Ola Fosheim Grøstad wrote:On Wednesday, 1 January 2020 at 22:04:00 UTC, IGotD- wrote:Yyou're all silly guys. Don't use floating point for currency, just make a Currency fixed point custom type.Using floating point is not recommended. For some fractional number it is actually impossible to store the value as a rational binary number. For example 8.90 would be stored as 8.89999999999+ (in reality this is binary values so just think of my example in an equivalent binary value case). This would lead to some rounding errors, especially when chaining several operations.No, not if you store as cents. You get the exact same values as with 53 bits integers with IEEE754. You have to pay atttentition to rounding mode, even-odd is common.You should go for a representation that always calculates the currency exact, down to the cent or whatever it is. Not doing so you might even be breaking the law for some appliances.Double will do that fine. As I said, same as integer. If you need half-cents, just multiply with 200 instead of 100. Or you could use millis (multiply by 1000).
Jan 02 2020
On Thursday, 2 January 2020 at 13:58:17 UTC, Basile B. wrote:Yyou're all silly guys. Don't use floating point for currency, just make a Currency fixed point custom type.Drop the adhominem. If you understand the floating point hardware specification then there are no issues with floating point.
Jan 02 2020
On Thu, 2020-01-02 at 14:34 +0000, Ola Fosheim Gr=C3=B8stad via Digitalmars= - d wrote:=20[=E2=80=A6]If you understand the floating point hardware specification then=20 there are no issues with floating point. =20I am not an expert in this, but I have seen lots of rants and arguments on this over the years. As I understand it the core problem is needing base 10 numbers not base 2 ones =E2=80=93 converting between them causes problems =E2=80=93 and usin= g hardware floating point does not have enough accuracy for compliance with requirements of FCA for financial calculations. There are various people on the ACCU general mailing list and the LJC emailing list who know much more about this than I do as they work on these things on a daily basis. I could ask there for pointers as to why money types are such an obsession.=20 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Road m: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk
Jan 02 2020
On Thursday, 2 January 2020 at 17:18:04 UTC, Russel Winder wrote:On Thu, 2020-01-02 at 14:34 +0000, Ola Fosheim Grøstad via Digitalmars- d wrote:Oh, I am not arguing that banking institutions should use base 2 floating point. 64 bit floating point base 2 can only represent 90 trillion cents with exact precision, so if they do calculations involving base 10 constants that could easily lead to problems... (And jurisdictions have various rules for how to deal with the sub-cent remainder I believe). But you have the same issues with bit-limited base-2 fixed point, and it is easy to make mistakes with fixed bit fix point in non-trivial formulas! So, if correctness is important then you could use decimal (the exact Pythonic numeric type), large base-10 floats (rare in hardware), or big-int rationals (in this case base2 is ok, you take care of the remainder at the end)... Power9 from IBM apparently has 128 bits floating point, and IIRC some IBM machines have base 10 floating point hardware, but that is rather esoteric... In the more mundane world of every-day-computing you have to be able to represent currency in web clients and in TypeScript/JavaScript 64bit IEEE754 is the only reasonable alternative. So if you want the same representation on the server and the client then it can be useful to use 64bit floating point. Although, it is sometimes useful to store them ints as Steve suggested.[…]If you understand the floating point hardware specification then there are no issues with floating point.I am not an expert in this, but I have seen lots of rants and arguments on this over the years. As I understand it the core problem is needing base 10 numbers not base 2 ones – converting between them causes problems – and using hardware floating point does not have enough accuracy for compliance with requirements of FCA for financial calculations.
Jan 02 2020
On Thursday, 2 January 2020 at 17:57:19 UTC, Ola Fosheim Grøstad wrote:Oh, I am not arguing that banking institutions should use base 2 floating point. 64 bit floating point base 2 can only represent 90 trillion cents with exact precision,Typo: 90 trillion USD, so 9000 trillion cents. I.e. the range is -2^53 to 2^53, so basically a 54 bit signed integer with exact representation.
Jan 02 2020
On Thursday, 2 January 2020 at 17:57:19 UTC, Ola Fosheim Grøstad wrote:So if you want the same representation on the server and the client then it can be useful to use 64bit floating point.Disagree with that. You shouldn't even do money calculations on the client side and thus you only need the representation of it and hence you can just send it formatted as a string. Of course if your client is not JS or anything similar then there is no problem since you can represent the value just fine.
Jan 02 2020
On Thursday, 2 January 2020 at 18:30:54 UTC, bauss wrote:You shouldn't even do money calculations on the client side and thus you only need the representation of it and hence you can just send it formatted as a string. Of course if your client is not JS or anything similar then there is no problem since you can represent the value just fine.As I've pointed out double can represent anything you can represent as 53 bits unsigned integers, so this is a non-issue... It can be very useful to do calculations on currencies on the client side, but you don't use it for any other purpose than display.
Jan 02 2020
On Thursday, 2 January 2020 at 19:03:47 UTC, Ola Fosheim Grøstad wrote:On Thursday, 2 January 2020 at 18:30:54 UTC, bauss wrote:I'll just throw out that Lua has no integer type: https://www.lua.org/pil/2.3.html I've never had a reason to avoid integers for performance reasons, but I suppose there are cases in which it's relevant...You shouldn't even do money calculations on the client side and thus you only need the representation of it and hence you can just send it formatted as a string. Of course if your client is not JS or anything similar then there is no problem since you can represent the value just fine.As I've pointed out double can represent anything you can represent as 53 bits unsigned integers, so this is a non-issue... It can be very useful to do calculations on currencies on the client side, but you don't use it for any other purpose than display.
Jan 02 2020
On Thursday, 2 January 2020 at 19:12:11 UTC, bachmeier wrote:I've never had a reason to avoid integers for performance reasons, but I suppose there are cases in which it's relevant...Scripting languages try to keep things simple, so having only one numeric type is an advantage from an implementation point of view. So, not really for performance. However, if you mean fixed point integers, then you need a rather big bit width to avoid overflow errors to do the same calculations as with floating point. And it is easy to make mistakes, but older DSPs didn't have floating point units so they used fixed point math (and also older computer games) and programmers had to be very clever to make it perform well with good accuracy. In some ways fixed point is more tiresome than writing in assembly if you try to do something nontrivial. E.g. in fixed point you would have to do 3% of 123 as (123*3+50)/100... Or 3.14% of 123 as (123*314+5000)/1000. Except division is slow so you would instead convert the divisor into a reciprocal and do a multiply instead (modern compilers do this for you if the divisor is known at compile time). So if the percentage isn't known at compile time you have much work to do as a programmer to get it right...
Jan 02 2020
On Thursday, 2 January 2020 at 19:25:08 UTC, Ola Fosheim Grøstad wrote:(123*3+50)/100... Or 3.14% of 123 as (123*314+5000)/1000.So easy to make mistakes with fixed point, should've been /10000...Except division is slow so you would instead convert the divisor into a reciprocal and do a multiply instead (modern compilers do this for you if the divisor is known at compile time).Well, in this specific case you could probably do result=percentage*value like this: result = (value*percentage_reciprocal+5)/10; but that is just one simple formula... it gets tricky real fast when trying to do something more advanced in fixed point efficiently and correctly.
Jan 02 2020
On Thursday, 2 January 2020 at 19:59:09 UTC, Ola Fosheim Grøstad wrote:On Thursday, 2 January 2020 at 19:25:08 UTC, Ola Fosheim Grøstad wrote:The devil goes even further if you want to account for negative numbers :) Integer rounding is actually kind of hellish vs floating-point rounding.(123*3+50)/100... Or 3.14% of 123 as (123*314+5000)/1000.So easy to make mistakes with fixed point, should've been /10000...
Jan 02 2020
On Thursday, 2 January 2020 at 19:12:11 UTC, bachmeier wrote:I'll just throw out that Lua has no integer type: https://www.lua.org/pil/2.3.html I've never had a reason to avoid integers for performance reasons, but I suppose there are cases in which it's relevant...Lua 5.3 (released five years ago) has got integers. The text you are linking is 17 years old.
Jan 02 2020
On Thursday, 2 January 2020 at 20:05:18 UTC, lithium iodate wrote:On Thursday, 2 January 2020 at 19:12:11 UTC, bachmeier wrote:Okay, I'm not a Lua expert, obviously. The point still stands that you can have a successful programming language without even having an integer type.I'll just throw out that Lua has no integer type: https://www.lua.org/pil/2.3.html I've never had a reason to avoid integers for performance reasons, but I suppose there are cases in which it's relevant...Lua 5.3 (released five years ago) has got integers. The text you are linking is 17 years old.
Jan 02 2020
On Thursday, 2 January 2020 at 21:03:42 UTC, bachmeier wrote:Okay, I'm not a Lua expert, obviously. The point still stands that you can have a successful programming language without even having an integer type.*cough* *cough* JavaScript *cough*
Jan 02 2020
On Thursday, 2 January 2020 at 21:31:02 UTC, JN wrote:On Thursday, 2 January 2020 at 21:03:42 UTC, bachmeier wrote:JavaScript has 32 bit integers as an implict type though.Okay, I'm not a Lua expert, obviously. The point still stands that you can have a successful programming language without even having an integer type.*cough* *cough* JavaScript *cough*
Jan 02 2020
On Thu, Jan 02, 2020 at 05:18:04PM +0000, Russel Winder via Digitalmars-d wrote: [...]As I understand it the core problem is needing base 10 numbers not base 2 ones – converting between them causes problems – and using hardware floating point does not have enough accuracy for compliance with requirements of FCA for financial calculations.AFAIK, the crux of the problem with using binary floating point types for money representation is that the former's base-2 rounding behaviour does not 100% match the latter's expected base-10 rounding behaviour. This discrepancy is a big problem because in financial applications 100% identical behaviour with base-10 rounding is a non-negotiable requirement. T -- Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr
Jan 02 2020
On Thursday, 2 January 2020 at 17:59:40 UTC, H. S. Teoh wrote:AFAIK, the crux of the problem with using binary floating point types for money representation is that the former's base-2 rounding behaviour does not 100% match the latter's expected base-10 rounding behaviour. This discrepancy is a big problem because in financial applications 100% identical behaviour with base-10 rounding is a non-negotiable requirement.You can set the rounding mode. Round to even is the common default I believe (bankers rounding). Although I think it is common to just round up at 0.5 when doing manual accounting. So you can get the same behaviour when storing in cents, but you then need to do the downscaling as the last step. So you need to take care to get correct results. E.g. to get 3% of 123 cents: (3*123.0)/100 Although 25% is no problem: 0.25*123.0 (since 0.25 has an exact representation in base 2 floating point) So it is easy to make mistakes. Same argument for fixed point. With base 10 representation that is no longer a problem. Same with base 2 rational, as you do the rounding in the last step.
Jan 02 2020
On Thursday, 2 January 2020 at 18:20:38 UTC, Ola Fosheim Grøstad wrote:E.g. to get 3% of 123 cents: (3*123.0)/100Whoops, too quick, that won't work. You need to set the rounding mode first and then do the truncating. E.g. you can do the same calculation twice with round up/round down and do basic rounding. If you get the same result, then it is right. But easy to make mistakes... like I just demonstrated.. :-P
Jan 02 2020
On Thursday, 2 January 2020 at 18:26:25 UTC, Ola Fosheim Grøstad wrote:truncating. E.g. you can do the same calculation twice with round up/round down and do basic rounding. If you get the same result, then it is right. But easy to make mistakes... like I just demonstrated.. :-PFor those interested there work done on a standard for doing exactly this (interval arithmetics) called IEEE1788: https://en.wikipedia.org/wiki/Interval_arithmetic#IEEE_Std_1788-2015_%E2%80%93_IEEE_standard_for_interval_arithmetic So all computations are done twice, once rounding up and once rounding down. If the error gets too large then you can switch to a slower algorithm. So then you can safely do base 2 floating points using fast hardware without all the issues and fall back on a slower base 10 software implementation where it fails.
Jan 02 2020
On Thursday, 2 January 2020 at 18:26:25 UTC, Ola Fosheim Grøstad wrote:On Thursday, 2 January 2020 at 18:20:38 UTC, Ola Fosheim Grøstad wrote:For the curious, on some FPUs you can test if the computations was inexact using the FE_INEXACT flag. So, then you can do all the computations and ensure that there is no information loss up to the division. Then you do an inexact division with rounding-down mode: // set rounding down mode here and track FE_INEXACT exception x = 3.0*value+0.5 // ensure that FE_INEXACT is false // do inexact computation result = floor(x/100.0) I think that should work out ok for all input values, but I've never actually used FE_INEXACT in practice, so maybe I got something wrong...E.g. to get 3% of 123 cents: (3*123.0)/100Whoops, too quick, that won't work.
Jan 02 2020
On Thursday, 2 January 2020 at 23:13:00 UTC, Ola Fosheim Grøstad wrote:// set rounding down mode here and track FE_INEXACT exception x = 3.0*value+0.5x = 3.0*value+50.0 … ;-) In addtion to the IEEE754 base10 D-implementation that exists as a dub package I found this implementation by Intel: https://software.intel.com/en-us/articles/intel-decimal-floating-point-math-library Clock cycle counts from 2018: https://www.lirmm.fr/arith18/papers/CorneaM_Decimal_ARITH18.pdf It apparently supports Linux, Windows and Mac so it might be worth creating bindings for it if nobody has done it already? This combined with IEEE1788 could be interesting, first do the computation with base2 hardware floats and revert to base 10 on failure. Base 2 is basically 100 times faster...
Jan 03 2020
On Thursday, 2 January 2020 at 18:20:38 UTC, Ola Fosheim Grøstad wrote:You can set the rounding mode. Round to even is the common default I believe (bankers rounding). Although I think it is common to just round up at 0.5 when doing manual accounting.You are right about this and the reason is that otherwise large numbers start being very inaccurate very fast.
Jan 02 2020
On Wednesday, 1 January 2020 at 18:16:01 UTC, Vitaly Livshic wrote:Thanks Steve, JN. JN, BigInt is big integer. It cannot works with fractional numbers. It is sadly, that wide-spread languages have no convinient money type. This is abnormal. Hope, D will have fixed point type either as built-in type or library.https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currencyIt cannot works with fractional numbers.Nothing can give you a better answer if your fraction is 176/100. You can always convert from int to some other type without losing precision on the initial calculations if you're in a situation where you want to calculate the per-unit cost for 37 units that cost a total of $500.17.
Jan 01 2020
On Wednesday, 1 January 2020 at 15:41:32 UTC, Vitaly Livshic wrote:Good day. I came from Java world, where 'double' type inadequate for money calculation. BigDecimal serves for it. This is ugly type, but gives precise results. Which type I must use for money in D?You can use this package: https://code.dlang.org/packages/money
Jan 01 2020
On Wednesday, 1 January 2020 at 15:41:32 UTC, Vitaly Livshic wrote:Good day. I came from Java world, where 'double' type inadequate for money calculation. BigDecimal serves for it. This is ugly type, but gives precise results. Which type I must use for money in D?Here you have a full IEE754-2008 compliant implementation of decimal data types (32, 64 and 128 bit). https://github.com/rumbu13/decimal Same as the Intel one proposed here by someone else, but written completely in D, no dependencies, no bindings.
Jan 04 2020