Thinking of sys::Decimal as the default Fantom decimal type it feels weird not to have a precision control over it.
How should one do financial calculations with no control of rounding for instance?
I'm not saying we should jump on clumsy MathContext API of Java's BigDecimal a few additional functions would suffice.
brianMon 29 Nov 2010
Any concrete suggestions?
We could just add a scale and toScale method?
jodastephenMon 29 Nov 2010
I've wondered if there is an option to use a 64 bit integer type and use pure functions to manipulate it.
Decimal a := 1.234
Decimal b := 2.345
Decimal c := a + b
// which becomes
long c = DecimalFns.plus(a, b); // Java
This would give decimals similar performance as other primitives, although its a lot of work to do. You'd also need a full BigDecimal for larger numbers. But it does work well for the main use case of simply getting accurate numbers. There is an IEEE standard for 64 bit decimals too which I remember seeing a Java library for.
brianMon 29 Nov 2010
I've wondered if there is an option to use a 64 bit integer type and use pure functions to manipulate it
This is how decimal works in C#, and is how I would prefer Fantom Decimal work too. Most people just want to use decimal for money, and the overhead of BigDecimal is probably excessive (that could always be exposed in a math pod). However, implementing decimal with a 64-bit long is a pretty big project that I wasn't ready to tackle. Do you know what library you saw that in?
jodastephenMon 29 Nov 2010
Agreed that it would be a big project (and the need to retain a BigDecimal).
I think this is the library. Although I've no idea how up to date or accurate it is.
Decimal round(RoundingMode mode := RoundingMode.halfEven) - rounds to the nearest integer value using given rounding type, mostly convenience function
where Rounding mode would be simply the same as in Java.
heliumTue 30 Nov 2010
.Net's decimal is 128 bits wide.
brianTue 30 Nov 2010
I'd really hate to have to add a RoundingMode enum into sys - is that something people really use? Or is it just over-engineering?
katoxTue 30 Nov 2010
I'm not very fond of making it more complicated but unfortunately this isn't the type of problem "one glove fits all".
Frequent usage:
half up - taught in school, very popular, biased (0.5 always get rounded up)
half to even - statistical rounding, free of overall bias, the default for financial computing ) and floating point operations (IEEE 754)
up / down - like floor and ceiling but rounded in direction from zero to +inf/-inf, default for arithmetic computing
Infrequent usage:
floor - cut the decimal part, used in engineering
ceiling - round nearest bigger integer (+1 if there is decimal part), used in engineering
stochastic - random up/down rounding, using in statistics
unnecessary - forcing an exception if rounding is needed
Almost never used
half down - complement to half up
half to odd - similar to half to even but preserves scale
Note: rounding modes were added on request in Java 5+. Dotnet System.Decimal supports half to even (the default) and arithmetic rounding (via MidporintRounding enum)
A real numeric tower is hard to efficiently implement without direct JVM support.
Regarding enhancements to Decimal, to tell the truth I am still a bit on the fence about adding all this stuff to 1.0. It seems to draw into revolving all Fantom's semantics around Java's BigDecimal and is that what we really want?
katoxWed 1 Dec 2010
@brian, I see you point. We take the less general way and implement it more like sys::Float.
Calls using toScale with different rounding modes would have to be emulated by shifting decimal point left scale places, calling floor/ceil, shifting right.
Change note: I'd leave the rounding default on halfUp because that is what JS and Java returns (unlike dotnet).
katox Sun 28 Nov 2010
Thinking of sys::Decimal as the default Fantom decimal type it feels weird not to have a precision control over it.
How should one do financial calculations with no control of rounding for instance?
I'm not saying we should jump on clumsy
MathContext
API of Java'sBigDecimal
a few additional functions would suffice.brian Mon 29 Nov 2010
Any concrete suggestions?
We could just add a
scale
andtoScale
method?jodastephen Mon 29 Nov 2010
I've wondered if there is an option to use a 64 bit integer type and use pure functions to manipulate it.
This would give decimals similar performance as other primitives, although its a lot of work to do. You'd also need a full BigDecimal for larger numbers. But it does work well for the main use case of simply getting accurate numbers. There is an IEEE standard for 64 bit decimals too which I remember seeing a Java library for.
brian Mon 29 Nov 2010
This is how
decimal
works in C#, and is how I would prefer FantomDecimal
work too. Most people just want to use decimal for money, and the overhead of BigDecimal is probably excessive (that could always be exposed in amath
pod). However, implementing decimal with a 64-bit long is a pretty big project that I wasn't ready to tackle. Do you know what library you saw that in?jodastephen Mon 29 Nov 2010
Agreed that it would be a big project (and the need to retain a BigDecimal).
I think this is the library. Although I've no idea how up to date or accurate it is.
katox Mon 29 Nov 2010
Yes, my thoughts were to add
Int scale()
- returning current scaleDecimal toScale(Int newScale, RoundingMode mode := RoundingMode.halfEven)
- expanding/shrinking (if possible) the scaleDecimal round(RoundingMode mode := RoundingMode.halfEven)
- rounds to the nearest integer value using given rounding type, mostly convenience functionwhere Rounding mode would be simply the same as in Java.
helium Tue 30 Nov 2010
.Net's decimal is 128 bits wide.
brian Tue 30 Nov 2010
I'd really hate to have to add a RoundingMode enum into sys - is that something people really use? Or is it just over-engineering?
katox Tue 30 Nov 2010
I'm not very fond of making it more complicated but unfortunately this isn't the type of problem "one glove fits all".
Frequent usage:
Infrequent usage:
Almost never used
Note: rounding modes were added on request in Java 5+. Dotnet
System.Decimal
supports half to even (the default) and arithmetic rounding (via MidporintRounding enum)dmoebius Wed 1 Dec 2010
+1 for a real number tower.
I've seen that in the Factor programming language, and it works.
brian Wed 1 Dec 2010
A real numeric tower is hard to efficiently implement without direct JVM support.
Regarding enhancements to Decimal, to tell the truth I am still a bit on the fence about adding all this stuff to 1.0. It seems to draw into revolving all Fantom's semantics around Java's BigDecimal and is that what we really want?
katox Wed 1 Dec 2010
@brian, I see you point. We take the less general way and implement it more like
sys::Float
.New operations
for
sys::Decimal
Int scale()
Decimal toScale(Int newScale, RoundingMode mode := RoundingMode.halfUp)
Decimal round(RoundingMode mode := RoundingMode.halfUp)
Decimal floor()
Decimal ceil()
and
RoundingMode
enum of two values onlyhalfUp
halfToEven
Calls using
toScale
with different rounding modes would have to be emulated by shifting decimal point leftscale
places, calling floor/ceil, shifting right.Change note: I'd leave the rounding default on
halfUp
because that is what JS and Java returns (unlike dotnet).Implementation
scale
toScale and round
round()
Decimal.Round(decimal, 0)
,Decimal.Round(decimal, 0, MidpointRounding.ToEven)
toScale()
Decimal.Round(decimal, newScale)
,Decimal.Round(decimal, newScale, MidpointRounding.ToEven)
-
round()
Decimal.Round(decimal, 0, MidpointRounding.AwayFromZero)
Math.round(decimal)
,decimal.toFixed(0)
toScale()
Decimal.Round(decimal, newScale, MidpointRounding.AwayFromZero)
decimal.toFixed(newScale)
ceil
floor
Unimplemented
These would need manual reimplementation in apps.