Paul D. Anderson wrote:
It looks like there's a lot of interest in getting bigfloat going. As I
mentioned I have some half-finished stuff so I'll dust it off and get going.
Most of the coding is straightforward. However --
An important implementation question is how to determine the "context" of an
operation (i.e. things like the precision and rounding method). This isn't often an issue
for normal floating point, but applications that need arbitrary precision frequently need
control of the context.
There are several ways to approach this.
First, the context can be a global setting that affects all operations from the
time it is set until it is changed. This is the simplest to implement and is
adequate if all bigfloat calculations use the same context most of the time. If
a different context is needed for some calculations, the user needs to save and
reset the settings.
Second, the context can be tied to the operation (this is how Java's BigDecimal
is implemented). There is a default context, but each operation has an optional
context parameter. This is also easy to implement but there is a problem for
languages like D which allow operator overloading -- there's no simple way to
add an additional parameter to an operation (opAdd, for instance). Of course
non-overloading operations [add(op1, op2, context)] can be used, but noone
wants to go there.
Third, each BigFloat object can carry it's own context. This makes the
objects larger, but they tend to be large anyway. A bigger issue is how to carry out an operation on two operands with different contexts. Some sort of tie-breaker has to be decided on (lowest precision wins?).
A fourth option is use subclasses and have a static context for each subclass.
Calculations requiring a particular context can use a separate subclass.
Implementation of this option would be more involved, especially if
interoperation of the subclasses is allowed (the same tie-breaking would be
needed as above).
------
I think the second and third options are non-starters. As noted, the first is
the simplest (and that's enough to get started with). The fourth option may be
where we want to end up, but there are an awful lot of details to be worked out.
Does anyone have strong feelings for/against any of these options??
Paul
My opinion -- precision should be a per-object setting, since it is a
property of the data. Rounding etc is a property of the operators and
functions and should be thread-local, and set by creating a scope struct
with a constructor that sets the mode to a new value, and a destructor
which restores it to the previous one.
eg
BigFloat a = 5e50;
BigFloat b = 1e-20;
{
BigFloatRounding(ROUND_DOWN); // applies until end of scope
a*=sin(b);
}
// we're back in round-to-nearest.