Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::numeric_limits::is_exact ... what is a usable definition?

As I interpret it, MSDN's definition of numeric_limits::is_exactis almost always false:

[all] calculations done on [this] type are free of rounding errors.

And IBM's definition is almost always true: (Or a circular definition, depending on how you read it)

a type that has exact representations for all its values

What I'm certain of is that I could store a 2 in both a double and a long and they would both be represented exactly.

I could then divide them both by 10 and neither would hold the mathematical result exactly.

Given any numeric data type T, what is the correct way to define std::numeric_limits<T>::is_exact?

Edit: I've posted what I think is an accurate answer to this question from details supplied in many answers. This answer is not a contender for the bounty.

like image 256
Drew Dormann Avatar asked Jan 07 '13 20:01

Drew Dormann


People also ask

What does Numeric_limits mean in C++?

std::numeric_limits ::digits in C++ with Example Return Value: The function std::numeric_limits<T>::digits returns the number of radix digits that the type can represent without loss of precision.

Which of the following data types is accepted by the Numeric_limits function?

Data types that supports std::numeric_limits() in C++ std::numeric_limits<int>::max() gives the maximum possible value we can store in type int. std::numeric_limits<unsigned int>::max()) gives the maximum possible value we can store in type unsigned int.


2 Answers

The definition in the standard (see NPE's answer) isn't very exact, is it? Instead, it's circular and vague.

Given that the IEC floating point standard has a concept of "inexact" numbers (and an inexact exception when a computation yields an inexact number), I suspect that this is the origin of the name is_exact. Note that of the standard types, is_exact is false only for float, double, and long double.

The intent is to indicate whether the type exactly represents all of the numbers of the underlying mathematical type. For integral types, the underlying mathematical type is some finite subset of the integers. Since each integral types exactly represents each and every one of the members of the subset of the integers targeted by that type, is_exact is true for all of the integral types. For floating point types, the underlying mathematical type is some finite range subset of the real numbers. (An example of a finite range subset is "all real numbers between 0 and 1".) There's no way to represent even a finite range subset of the reals exactly; almost all are uncomputable. The IEC/IEEE format makes matters even worse. With that format, computers can't even represent a finite range subset of the rational numbers exactly (let alone a finite range subset of the computable numbers).

I suspect that the origin of the term is_exact is the long-standing concept of "inexact" numbers in various floating point representation models. Perhaps a better name would have been is_complete.

Addendum
The numeric types defined by the language aren't the be-all and end-all of representations of "numbers". A fixed point representation is essentially the integers, so they too would be exact (no holes in the representation). Representing the rationals as a pair of standard integral types (e.g., int/int) would not be exact, but a class that represented the rationals as a Bignum pair would, at least theoretically, be "exact".

What about the reals? There's no way to represent the reals exactly because almost all of the reals are not computable. The best we could possibly do with computers is the computable numbers. That would require representing a number as some algorithm. While this might be useful theoretically, from a practical standpoint, it's not that useful at all.

Second Addendum
The place to start is with the standard. Both C++03 and C++11 define is_exact as being

True if the type uses an exact representation.

That is both vague and circular. It's meaningless. Not quite so meaningless is that integer types (char, short, int, long, etc.) are "exact" by fiat:

All integer types are exact, ...

What about other arithmetic types? The first thing to note is that the only other arithmetic types are the floating point types float, double, and long double (3.9.1/8):

There are three floating point types: float, double, and long double. ... The value representation of floating-point types is implementation-defined. Integral and floating types are collectively called arithmetic types.

The meaning of the floating point types in C++ is markedly murky. Compare with Fortran:

A real datum is a processor approximation to the value of a real number.

Compare with ISO/IEC 10967-1, Language independent arithmetic (which the C++ standards reference in footnotes, but never as a normative reference):

A floating point type F shall be a finite subset of ℝ.

C++ on the other hand is moot with regard to what the floating point types are supposed to represent. As far as I can tell, an implementation could get away with making float a synonym for int, double a synonym for long, and long double a synonym for long long.

Once more from the standards on is_exact:

... but not all exact types are integer. For example, rational and fixed-exponent representations are exact but not integer.

This obviously doesn't apply to user-developed extensions for the simple reason that users are not allowed to define std::whatever<MyType>. Do that and you're invoking undefined behavior. This final clause can only pertain to implementations that

  • Define float, double, and long double in some peculiar way, or
  • Provide some non-standard rational or fixed point type as an arithmetic type and decide to provide a std::numeric_limits<non_standard_type> for these non-standard extensions.
like image 124
David Hammen Avatar answered Nov 10 '22 00:11

David Hammen


I suggest that is_exact is true iff all literals of that type have their exact value. So is_exact is false for the floating types because the value of literal 0.1 is not exactly 0.1.

Per Christian Rau's comment, we can instead define is_exact to be true when the results of the four arithmetic operations between any two values of the type are either out of range or can be represented exactly, using the definitions of the operations for that type (i.e., truncating integer division, unsigned wraparound). With this definition you can cavil that floating-point operations are defined to produce the nearest representable value. Don't :-)

like image 41
Hyman Rosen Avatar answered Nov 10 '22 00:11

Hyman Rosen