lmi
[Top][All Lists]
Advanced

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

Re: [lmi] Why not DBL_MAX?


From: Greg Chicares
Subject: Re: [lmi] Why not DBL_MAX?
Date: Mon, 26 Mar 2007 13:57:30 +0000
User-agent: Thunderbird 1.5.0.4 (Windows/20060516)

On 2007-3-26 10:05 UTC, Evgeniy Tarassov wrote:
> On 3/24/07, Greg Chicares <address@hidden> wrote:
>> 20070316T1310Z_DBL_MAX_to_static_limit_maximum.patch
> [...]
>> makes good sense. But why use this:
>>     double stratified_entity::limit_maximum = DBL_MAX;
>> instead of just writing DBL_MAX?
> 
> Only to simplify the code. So that the same constant is named the same
> way everywhere it is used. And of course only where it has the same
> semantics.

This limit is inherent in the problem domain: the last interval
has no finite upper bound in the real-number system. I find it
less simple to express that other than by DBL_MAX in computer
floating point.

This patch would also change a 'my_*' file. Such files have
proprietary versions that are used only to build programs that
create product files--programs that aren't distributed, and
whose source doesn't appear in any public cvs. Any change in a
public version calls for changes in the proprietary version;
it's not obviously certain that they won't be problematic in
some surprising way. I'd rather not open that can of worms.

>> Is there some arcane reason, e.g., that this quantity:
>>     static double const max_double = std::numeric_limits<double>::max();
>> in a removed line might not equal DBL_MAX for some woeful
>> compiler? (Really old versions of MinGW gcc did have an
>> incorrect value for DBL_EPSILON.)
> 
> I don't know, but using the same value (DBL_MAX or
> stratified_entity::limit_maximum), it ensures that the program will
> not produce bogus output for such a compiler.

If we're really concerned that
>>     static double const max_double = std::numeric_limits<double>::max();
doesn't equal DBL_MAX, then we could change 'tier_view_editor.cpp':

-        limits().push_back(max_double);
+        limits().push_back(DBL_MAX);

But I feel safe assuming that we won't use a compiler that gets
this wrong. If I didn't, I'd add a unit test for it (or you
might instead add a './configure' test; but I'm not advocating
that).

>> Is the reason that the value might change someday? If so,
>> why? So that we could make the algorithms that use it
>> correct even for infinity? Or so that we could restrict
>> them to "plausible" values, recognizing that we're really
>> operating on currency and no one has even 1e37 dollars?

[BTW, I don't see those as good reasons.]

> Two reasons for me to introduce such a constant was:
> 1) to make understanding and grepping the source code easier. If
> additionally we introduce another static double in 'sigfpe.cpp' then

I don't think you mean the SIGFPE handler, but no matter.

If you really did mean that file, then I ought to explain that
it seems not to do much with gcc on msw (where I think the unit
test in that file cannot be made to work), and AFAIK it's
untested on other platforms. I'll say that in its documentation.

> by grepping 'limit_maximum' one will only find occurences of this
> constant for cases where it is used for stratified_entity limit array
> values 'terminator'. When one sees DBL_MAX it only says the exact
> value, not the real meaning of the constant in the local context.

I hear you, but I believe DBL_MAX *is* the meaning: one cannot
understand why a fixed upper limit exists without also seeing
why it must be DBL_MAX.

'stratified_algorithms.hpp' works only with double (and we don't
have a need to use any other type). The limit has to be the
highest representable value for that type: that's inherent in
the nature of these algorithms. The documentation in that header
speaks of 'infinite' and 'infinity':

///        cumulative
///   rate   limit
///   0.05    1000    <-- first  bracket: [   0, 1000)
///   0.02    5000    <-- second bracket: [1000, 5000)
///   0.01 infinity   <-- third  bracket: [5000, infinity]
[I'll change that: 's/infinity]/infinity)/']
///
/// Limits are constrained to be positive and nondecreasing. The first
/// bracket extends from zero (implicitly) to the first limit. The last
/// limit is implicitly infinite.

[I'll replace the last line with this:
/// limit must have no finite upper bound in the real number system; in
/// computer floating point, it's specified as DBL_MAX.
]

because it's defining the problem in terms of the real number
system. If it's not sufficiently clear with the above changes,
then let's further improve that documentation of the problem
domain. But I don't want to change old code in a way that, to me
at least, makes it less clear to those who have already read its
documentation and understood the problem domain.

We could have made the upper bound implicit in the GUI, by
preventing users from specifying it--for example, by forbidding
them from typing anything in the last row of the second column.
I didn't do that in the legacy system, though it would have
avoided the need to format DBL_MAX in a way that makes sense to
users. If you can think of a good way to handle that problem,
then the GUI might not need to know about this upper limit;
otherwise, it can't be written without understanding this part
of the problem domain.

The real problem is that we use DBL_MAX at all:
    // TODO ?? This is ghastly. As designed, the last limit must
    // exist, and it must equal std::numeric_limits<T>::max(); but
    // comparing that value to a stored copy for exact equality has
    // an indeterminate result. As a temporary workaround here, the
    // last value is ignored.
Instead of seeking an alternative way of expressing the
dependency, maybe we can remove it when we convert the product
files to xml, and find a way to get it out of the GUI. This can
wait until later, unless you see a way to do it now that saves
work we'd otherwise have to do.

BTW, does the GUI enforce the other problem-domain constraints?
  /// Limits are constrained to be positive and nondecreasing.
Those constraints really do need to exist in the code, and the
GUI should enforce them. I'd rather reuse is_sorted() in file
'stl_extensions.hpp' than rewrite it, of course: it uses an
sgi implementation that's been widely exposed for years.

> 2) to get rid of the repeating line
> #include <cfloat> // DBL_MAX

Actually, I don't agree that this is a benefit. If it is, then
we could gain the same benefit by including that header in a
'stratified_*' header. But if it were included there, I'd
remove it, because those headers don't use it.

If it were impossible to use those headers in any way without
the definition of DBL_MAX, then I might say otherwise.

This comes back to Lakos's physical-design principles. One goal
is to include as little as possible in headers. One effect is
that numerous '.cpp' files may need to include a header, and he
would accept that--that's not what he's trying to minimize. If
it were, then the simplest design, and the easiest to maintain,
would use one master header that includes every header that we
use anywhere. Builds would then be slow; that's a major aspect
of the problem he's trying to solve.

If you want to propose some alternative set of well-articulated
principles, I'm open to a discussion based on the merits. The
Lakos book is old, and there may be a better way now. Or maybe
nobody has written a replacement for it because there's little
to add or change. Until we find a better alternative, though,
let's use the guidelines we've got.





reply via email to

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