lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Numerics


From: Vadim Zeitlin
Subject: Re: [lmi] Numerics
Date: Fri, 13 May 2016 16:55:59 +0200

On Mon, 9 May 2016 04:04:10 +0000 Greg Chicares <address@hidden> wrote:

GC> > 2. What API for rounding would you like to see.
GC> 
GC> No rounding API at all.

 I'd like to return to this discussion because I'm still very confused by
your view of this currency class.


[discussing the relative tolerance]
GC> Python makes an arbitrary choice:
GC>   https://www.python.org/dev/peps/pep-0485/#defaults

 I'm not convinced by the reasoning here. The fact is that most often the
exact tolerance doesn't matter, so any not completely unreasonable value
will do. But then sometimes it does and you have to change the default
value. And IME this always happens, for whichever value you choose.

 BTW, if you ever need PEP 485 in C++, there is this class at
https://github.com/philsquared/Catch/blob/master/include/internal/catch_approx.hpp
which implements exactly the same approach AFAICS.

GC> See the comments preceding that definition, which even cite TAoCP
GC> (which gave me occasion to open that book twice in one nychthemeron,

 As an aside, considering that there is a common "native" word meaning "24
hour interval" in Russian, I'd like to be able to use this word [more], but
I have some doubts about whether I'm going to be understood if I do.
Especially because I have no idea about how to pronounce it in English. And
in French it doesn't help that it sounds like a common profanity.

GC> only to find that Knuth doesn't discuss how to choose a value for
GC> his ε, alas).

 We already know that Knuth is wise...


GC> The problem was misstated; I should have written:
GC>   double factor u = 1 + .0024662698;
GC>   currency x = 123.45;      // Okay.
GC>   double z = u * x.value(); // Okay: 123.75446100681
GC>   x = from_value(z);        // Error: rounding details not specified.
GC> 
GC> In one circumstance, I might need the floor 123.75; in another, I
GC> might need the ceiling 123.76 . If from_value() chooses a rounding
GC> direction for me, then the answer must be wrong in one of those
GC> circumstances.

 Very well. Then we must always pass it the rounding method. What bothers
me with this approach is the line

        currency x = 123.45;

It doesn't use any rounding method, yet you expect it to compile. How can
this work? The consistent thing to do here is to disallow such assignment
as well.

 The only alternative I see is to use C++11 user-defined literals, then we
could allow

        currency x = 123.45_dollars;

and check -- during compile-time! -- that there are at most two digits
after the period here. Not sure if this is worth the trouble though (but
I'd love to try).

GC> Note: "123.76" above is really something like
GC>   123.75999999999997
GC> but it's "near enough" to an integer (12376) with the decimal point shifted
GC> two places to the left. The same cannot be said of 123.75446100681 .

 The words "near enough" imply that you select an ε. I'd rather avoid this.

GC> >  If we need other rounding modes, I think they should be provided by this
GC> > class itself, e.g. from_value() could take rounding_style
GC> 
GC> It might be better to write supplemental rounding functions that take
GC> double arguments and return currency.

 This is, IMHO, purely a question of taste. I don't have any strong
preference here and could see either being used.

 However, combined with your refusal of exposing "total_cents" in any way,
this would leave us with a class with value-like semantics without any
non-default constructors which is somewhat unusual.

 In this way, the rounding discussion merges with the total_cents one as I
think it's not really logical to both view the currency class as just a
fancy double (which is, I think, your approach) and simultaneously disallow
constructing it from double implicitly, without specifying the rounding
method. It seems more consistent to view currency as an integer (total
number of cents) which can be constructed from doubles rounded to two
decimal places to me.

 If you happen to agree with the latter statement, then I really think we
should expose total_cents and both allow constructing currency objects from
integer amounts of cents and retrieving this amount from them.


 To summarize: your arguments make it clear that currency can't be
implicitly created from double because a rounding method always needs to be
specified. This means that the only way to create a currency object without
rounding is from its string representation. This is inconvenient at least
for the tests and will IMO also be bothersome in normal use, which is why
I'd like to also have a ctor from the total number of cents and the
corresponding accessor. This would allow to use integers instead of strings
when serializing currency objects too, as a side effect, which can't be
bad.

 What do you think?
VZ


reply via email to

[Prev in Thread] Current Thread [Next in Thread]