[boost] Re: Fixed-Point Decimal Formal Review

2003-07-22 Thread Bill Seymour
Despite the several yes votes (thanks), I think I have to agree
with Ilya and vote no for my own library.  Of the problems
that have been mentioned, two, IMO, are show-stoppers:
the problem with the scale being immutable resulting in
inequality after assignment (if the scale isn't part of
the type), and the need for a floating-point decimal type
to hold intermediate results.

(Ilya, you're right that I haven't responded to the latter
issue.  It's not that I haven't read your posts, but rather
that I didn't think I had anything intelligent to say yet.
Please don't take it personally.)

Also, I got a note this morning from Raymond Mak of IBM in
Toronto who will be proposing a floating-point decimal TR
at the J11/WG14 session in Kona.  It's based on the proposed
IEEE 754 that Mike Cowlishaw mentioned in another Boost post.

So even if the current version of the library is accepted
into Boost, I'll be going back to the drawing board anyway.
Maybe acceptance is premature at this point.

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Fixed-Decimal's Scale

2003-07-19 Thread Bill Seymour
I've been thinking about the related issues of whether decimal
should be a template and whether the scale should be immutable.

First, I'm adamant that the user should be able to write

  dollars = foo;

without magically losing pennies or gaining mils; and I don't
think the user should have to type something like

  dollars.assign_without_changing_frac_digits(foo);

as a workaround to get that behavior.

Given that, then as Daryle has correctly pointed out, standard
library sequence collections of decimals, and mutating algorithms
that work on sequences of decimals, don't work right unless all
objects in the sequence have the same scale.  This issue of
working right must be addressed before we worry about efficiency
or the size of the objects.

1.  The scale could be part of the type (decimal becomes a class
template).

2.  A warning could be put in the documentation that says that
storing decimals of different scales in the standard collections
yields undefined behavior.

3.  I could try to work some other kind of magic.

The main difference I see between 1 and 2 is whether it's possible
for the user to make the mistake.  In neither can we have collections
of different scales; but I now think that ought to be allowed if
there's some way I can make it work.  (Note, for example, that with
either of the first two solutions, 1, 1.2 and 1.23 can't be sorted!)
So I'd like to try 3, at least as a mind experiment, before deciding
on 1 or 2.

Note that copy construction works correctly; it's just assignment
that has the perverse behavior.

Let's say I specialize std::swap() to swap scale as well as value,
and then specialize other standard algorithms to use swap where
they might otherwise use assignment.  Have I done enough?

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Thoughts on fixdec

2003-07-17 Thread Bill Seymour
Fernando Cacciola wrote:

 I'm inclined toward boost::numeric.


Two votes for boost::numeric.


 I prefer just 'decimal' because most decimal numbers I know of
 are fixed-point.  So I think 'fixed' can be left implicit.


Two votes (including mine) for decimal; two votes (including
Michel Andre's from a while back) for fixed_decimal.


 Couldn't [overflow/underflow checks] be provided as a postcondition,
 in terms of BOOST_ASSERT?


I'll consider that.

Fernando:

 Me:
 
  Daryle:
  
   6. There should only be conversions from strings, and _no_
   mixed operations with strings.
  
 
  In the absence of decimal literals, I think it's easier for the
  user to be able to use strings as pseudo-literals in all contexts;
  and I don't see how the mixed operations do any harm.
 

 The problem is that quite unfortunately, string literals are just
 pointers to constant char, but such pointers are also used to access
 raw memory, so, char const* is the target to implicit conversions
 from a lot more than string literals. This would lead to unexpected
 implicit conversions.


But I think that C++ inherits that part of the spirit of C that
says, Trust the programmer.  It's not that all programmers are
trustworthy, nor even that some programmers are always trustworthy.
It's that many programmers become increasingly trustworthy as they
gain more experience; and we want to reward that behavior. 8-)

Fernando:

 Me:
 
  Daryle:
   
   13. You have strange (regular) assignment semantics.  You try to
   change the receiver's logical value to the source's logical value,
   but retain the receiver's original scale (internally shifting the
   new significand and doing any rounding if needed).  ... you will
   get strange effects if you try to change containers of decimal
   through assignment.
 
  I thought it would be less surprising if a decimal object's scale
  were immutable.  This matches prior art (the BCD type on IBM
  mainframes, for example) in which the scale is part of the type.
 
  You're right about containerdecimal; but remember that this class
  isn't intended for number-crunching; so I don't really care about
  assigning matrices, etc.
 

 But this isn't about assigning matrices and number-crunching, it's
 about C++ assignment semantics.   The postcondition of equivalence
 for assignment is a strongly fundamental feature of the C++ object
 model, and everything and everyone, not just containers, relies on
 that.
 

Hmm...

I came up with two use cases:  figuring the final payment of a loan
and converting currency.  In both cases, I had to write the code
very carefully to /create/ the error I was worried about; and even
after doing so, neither case was particularly compelling.  You
might have convinced me.

Also, when considering the case of converting currencies, I saw
a problem with multiplication not being commutative:

  decimal dollars(2, 314.75);
  decimal exchange_rate(6, 0.890004);
  decimal euros(2);
 #if ONE_WAY_TO_DO_IT
  euros [round_up]= exchange_rate * dollars;
 #else
  euros = dollars [round_up]* exchange_rate;
 #endif

Programmers would have to be very careful with such code in any event;
so maybe my argument isn't a good one.

I still have an /emotional/ attachment to it, though.
I'll work on that. 8-)

Question:  should I go back to templateint Scale class decimal?

Advantages:  The assignment semantics issue goes away because
 the scale is part of the type.

 It's more like prior art.

Disadvantages:  The scale must be a constant expression.

There are member template issues with some compilers.

It won't work at all with MSVC v5 which can't deduce
non-type template arguments.  (OK, I could bite
the bullet and maintain a non-Boost version
for my own use at work; but I wouldn't be happy
about it.)

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Questions on fixdec

2003-07-17 Thread Bill Seymour
Ilya,

1.  You want the scale to be a template parameter so that it's part
of the type.  I've just raised this issue again; and I expect
there to be some discussion about it.  Stay tuned.  8-)

2.  You also want the rounding mode to be part of the type.  That
binds the rounding mode to the operand instead of to the
operator; but I've already chosen the latter.  We could reopen
that discussion if you want to; but I haven't gotten any other
complaints.

3.  You want the internal representation to be a single 64-bit
integer to make the object smaller.  Why?

For efficiency?  Do you think it would be faster to calculate
the representation of unity for each operation?

For decreased memory usage?  Are you doing embedded systems work?

Somebody said, Premature optimization is the root of all evil.
I can't remember who that was (Knuth?  Djikstra?); but somebody
else on the list will probably tell us.

4.  I haven't looked at your example code in detail yet; but at first
glance, it looks like you're confusing the precision (the maximum
number of representable digits) with the scale (the number of
digits to the right of the decimal point).

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Formal Review: fixed-point decimal library

2003-07-17 Thread Bill Seymour
Paul Bristow wrote:

 Overall I vote to accept this in the Boost library.


Thanks.


 There are some warnings using 'strict' which are probably
 cast avoidable:

 fixed_decimal.hpp(442) : warning C4389: '==' : signed/unsigned mismatch
 fixed_decimal.hpp(446) : warning C4018: '' : signed/unsigned mismatch
 fixed_decimal.hpp(450) : warning C4018: '' : signed/unsigned mismatch


Fixed.


 I believe the best namespace is numeric.


Three votes for boost::numeric.  It looks like that's the consensus.


 I really don't like the name scale at all.


Isn't that the correct term?


 Nor deffrac, decscale and iosprec. Can't we do better than this,
 even if longer?


Suggestions?


 The documentation is mainly pitched at a too high a level
 for users ...

 [other suggestions]


OK, I'll try to simplify it and add more examples.

As regards the need for a decent test program, with which I agree
completely, my plan now is to have three of them.

- One, built around the Boost test framework, just tests whether
  the various operators and free functions are doing the arithmetic
  right.

- A second, which instantiates all the output-related templates,
  writes some interesting values like numeric_limitsdecimal::min()
  and tests the correct operations of the I/O manipulators and
  rounding modes (as arguments to operator), locales, and narrow
  and wide streams.

- A third which instantiates all the input-related templates and
  does the same kind of tests except that the user will have to
  enter some ad hoc values.

For the second and third test programs, because locale strings
are implementation-specific, they'd be entered as command-line
arguments.

Does that seem sufficient?

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Thoughts on fixdec

2003-07-16 Thread Bill Seymour
 the scale is part of the type.

You're right about containerdecimal; but remember that this class
isn't intended for number-crunching; so I don't really care about
assigning matrices, etc.


 14.   If you have a scale member function to return the current
 object's scale; you should have something like a significand member
 function to return the object's mantissa.  This will allow copies of
 objects that retain just one aspect of their source.


 15.   It took me a while to figure the following out, so maybe you
 should put it in simpler language.  Objects of this type retain a
 copy of the given value, rounded (via the given mode) and kept to
 a precision of the given scale number of (base-ten) fractional digits.
 The value is stored as that scale and the (integral) number of
 10**(-scale) units needed to add up to the value.


I'm not sure what you mean.


 I guess that the scale needs to be non-negative?


Yes, and that's pointed out in the documentation, but maybe not
loudly enough.


 16. ... the [] is bound to the object on the left (by C++'s parsing
 rules), and not to the operator.  You just adjust the spacing and wish
 that the brackets were associated with the operator on the right.


Yes, and that's pointed out in the documentation with a box around it;
and there's a rather long bit (maybe even too long) that explains how
the whole business came into being.


 17.   Do you really need to support VC++5 ...?


Yes, I do, because that's what I'm stuck with at work (for what are
euphemistically called non-technical reasons).  I understand
completely that such support is not required for Boost; but absence
of a requirement isn't a requirement of absence; and I don't see
that the additional support does any harm.  (Users have to hack
their visualc.hpp to let that version pass anyway.)

Thanks for the input.

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Formal Review: fixed-point decimal library

2003-07-15 Thread Bill Seymour
Fernando,

Thanks for your input.

The scale really is intended to be the number of decimal digits
to the right of the decimal point; so, yes, if int_type on your
system is 64 bits, and if you specify a scale of 18, then no
/whole/ decimal digits will be allowed to the left of the point.
(You might get a 19th digit if it isn't too big.)

One of your tests, for example:

 s=2147483647
 [9,s]=2147483647.0
 [10,s]=302809239.6290448384


Trying to construct the decimal with a scale of 10 results in
signed integer overflow which yields undefined behavior.


 Here is a list of other minor issues:
 =

 I don't think that is_bounded and is_modulo should be inherited
 from int_type.

 is_bounded is intended to be false only for those types which
 can represent numbers in any range. Even if int_type were
 unbounded (is_bounded=false), decimal itself will always
 be bounded, ...


Why?


 Similarly, is_modulo tells whether the numeric type uses 
 modulo arithmetic, as do the unsigned integral types,
 yet decimal does not do that ...


I don't see this.  If int_type just wraps around on overflow,
then why wouldn't the decimal type itself do the same?


 ... even if int_type where unsigned, ...


int_type can't be unsigned.


 Currently, the library cannot be put in a precompiled header
 using BCC because of the 'max_val,min_val' constants. This
 can be solved by making those constants inlined functions.


But then they wouldn't be constants, would they?


 The documentation is clearly written with some 'old' version
 in mind. I think all references and comparisons with that
 older version should be removed from the docs, or at least,
 put aside on a 'history' section.


OK.


 IMO the documentation should begin with a brief (but complete)
 overview of what is a 'fixed decimal' number, including the
 concept of a 'scale' (or 'digits' as I much prefer), and of
 rounding modes.


I was reticent to do this for fear of talking down to my audience.
I can add more introductory material if others think it would be
a good idea.


 I understand why it is not supported to construct a decimal
 from an int_type, but I think that construction from
 'unsigned int' should be supported ...


I'll be happy to put that in if you can give me a use case for it.


 The docs say:

 The conversion will be exact if the string contains no more
 than scale digits to the right of the decimal point; otherwise
 the value will be rounded as specified

 This is incorrect, I think. If the string contains more than
 (scale+1) digits, whether to the left or right of the decimal
 point (or both), rounding will ocurr.


I think the documentation is basically correct; although if
n * scale**10 can't fit in an int_type, then the behavior is
undefined; so I guess rounding could occur in that case. 8-)

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Formal Review: fixed-point decimal library

2003-07-15 Thread Bill Seymour
Fernando Cacciola wrote:

 OK.
 So, correct me if I'm wrong:
 For any given decimal with some int_type, a 'digits' constant is
 associated with it which comes from numeric_limitsint_type::digits10.
 This constant identifies the maxium number of digits (in both the
 whole and fractional parts) that any such decimal can represent.


Right, it's the /precision/ (the total number of representable
digits).  Consider, for example, numeric_limitsint::digits10
on an implementation with 32-bit ints.  This value will be 9
because all 9-digit values are representable.  There will also
be some some 10-digit values that are representable (if the MSD
is in [-2,2]).


 Thus numeric_limitsdecimal::digits and digits10 are equal to
 this constant.


Yes, and the two values are equal to each other because
numeric_limitsdecimal::radix is 10.


 The scale 's' given by the user specifies the desired number of
 decimal digits.


I would say digits to the right of the decimal point.  (Digits
to the left of the point I would also call decimal because
they're base-10.)


 It cannot be  '(digits-1'), ...


Yes, the scale can be equal to the precision (which I believe is
what you're calling digits); but then, in general, there won't be
any digits to the left of the point.  (As with the example above
with numeric_limitsint::digits10, there could be one valid digit
to the left of the point if it's not too large.)


 I'd put a description like the one above in the docs so that the
 limit on total number of digits and its relation with the scale
 is well documented.


Agreed.

 
  Why? [can't decimal be unbounded]
 
 Because it has a constant max_scale.


Ah, so.  Yes, I see that now.  Good catch.

 
  I don't see this.  If int_type just wraps around on overflow,
  then why wouldn't the decimal type itself do the same?

 Because decimal has its own arithmetic.
 For instance, would decimal::add/mul wrap around even if
 int_type would?

Yes, I think you're right about that.  OK, is_bounded should be true
and is_modulo should be false.  I'll fix that.

Re the max_val, min_val and max_scale constants:  there was some
reason that I wanted them to be constant expressions.  I'll reconsider
that; but I don't want to promise a change right now.

Re construction from unsigned int:  I think you gave a good reason
to allow it.  I'm pretty busy at my day job right now, so I can't
promise a quick change; but I agree with you.


 If the concept of 'digits' is formalized, alon with its relation
 to 'scale', then this statement could simply say that The conversion
 will be exact if the string contains no more than 'digits()' digits
 (whole and/or decimal)


I don't think that's right.  I can assign 123.45 to a decimal with
a scale of 2 without rounding.  Do I misunderstand what you're
saying?

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: Formal Review: fixed-point decimal library

2003-07-15 Thread Bill Seymour
I've upload fixdec23.zip to the Yahoo files section.

I made some changes that Jens suggested to allow compiling with
Comeau and gcc; and I've made the is_bounded and is_modulo fixes
that Fernando suggested along with interoperatability with
unsigned as well as int.

Fernando,

I think that max_scale needs to be a constant expression
because it's used in the definition of numeric_limitsdecimal:

  BOOST_STATIC_CONSTANT(int, digits=boost::fixdec::max_scale);
  BOOST_STATIC_CONSTANT(int, digits10=boost::fixdec::max_scale);

And I think I'm right about numeric_limits::digits10.  I believe
it's intended to be mean that, if the value is N, then /all/ N-digit
numbers can be represented.  numeric_limitsdecimal::digits10 can't
be 19 because only a subset of 19-digit numbers are representable.

Also, I think that your statement:

 ... __int64 support 18 digits at most.

is factually incorrect.  Your implementation's __int64 should support
anything up to 10**63 - 1 or (with commas as thousands separators)
9,223,372,036,854,775,807.  That's a 19-digit number.

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Formal Review Request, Fixed-Point Decimal Library

2003-01-29 Thread Bill Seymour
Now that I once again have the time to pay attention to what's
going on in Boost, I'd like to request a formal review of the
fixed-point decimal library in fixdecv2.zip in the Yahoo files
section.

I haven't made any changes since I uploaded that file last October.

Thanks,

--Bill Seymour

___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost