19

PHP has a decimal type, which doesn't have the "inaccuracy" of floats and doubles, so that 2.5 + 2.5 = 5 and not 4.999999999978325 or something like that.

So I wonder if there is such a data type implementation for C or C++?

dtech
  • 44,350
  • 16
  • 93
  • 165

7 Answers7

22

The Boost.Multiprecision library has a decimal based floating point template class called cpp_dec_float, for which you can specify any precision you want.

#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>

int main()
{
    namespace mp = boost::multiprecision;
    // here I'm using a predefined type that stores 100 digits,
    // but you can create custom types very easily with any level
    // of precision you want.
    typedef mp::cpp_dec_float_100 decimal;

    decimal tiny("0.0000000000000000000000000000000000000000000001");
    decimal huge("100000000000000000000000000000000000000000000000");
    decimal a = tiny;         

    while (a != huge)
    {
        std::cout.precision(100);
        std::cout << std::fixed << a << '\n';
        a *= 10;
    }    
}
Benjamin Lindley
  • 95,516
  • 8
  • 172
  • 256
7

Yes:

There are arbitrary precision libraries for C++.
A good example is The GNU Multiple Precision arithmetic library.

Eric Postpischil
  • 141,624
  • 10
  • 138
  • 247
Martin York
  • 234,851
  • 74
  • 306
  • 532
  • 2
    Note that this will not actually "solve" the general problem: it will postpone it to a deeper precision level you can choose. Better than nothing, but -unfortunately- just one step beyond, towards the impossible "infinite precision". Nice tip, anyway! – Emilio Garavaglia Mar 12 '13 at 07:48
  • @EmilioGaravaglia: No. Arbitrary precision means exactly that. It does maths exactly. The only limitation is the memory on your machine to represent the numbers. – Martin York Mar 12 '13 at 08:14
  • 3
    what is the point is saying "No:" and then describing the exact same concept with different wording? What the "no" stands for? – Emilio Garavaglia Mar 12 '13 at 14:27
  • 2
    @EmilioGaravaglia: No. Not the same. You are implying that there is a limitation in precision. There is not. Its like saying one step towards bigger integers. We can have integers as large as you like (as long as you have memory for it). – Martin York Mar 12 '13 at 18:21
  • 2
    "As large as you like" < "infinite". You always have to round somehow. Only an infinite machine can do infinite precision calculations. It's not an opinion, but a demonstrated theorem. The OP is asking for an exact decimal 3*(10/3)==10. There is no such decimal, whatever long. – Emilio Garavaglia Mar 12 '13 at 19:21
  • 2
    @EmilioGaravaglia: Not true. And easy to show as false. You represent 1/3 (one third) as two integers (1 and a 3). That's how some of these libraries work (not sure if gmp does it this way but I would suspect). Its exact to infinite precision. So each number is represented as a pair (a enumerator and a denominator). Multiplication/Division affects the appropriate part of the number. So (3+1/3) * 9 = 30. (Exactly). – Martin York Mar 12 '13 at 19:35
  • 2
    That's not "infinite precision", since the denominator has an upper limit. It is just a better approximation. Even if you represent a number in "rational form", given a bit-size, there are always fractions that cannot be represented into that bitsize. This is always true for whatever number representation based on a "finite space". The fact 10/3 can fit a "pair if ints" is not a demonstartion – Emilio Garavaglia Mar 13 '13 at 09:00
  • 1
    @EmilioGaravaglia: Then you use more bits. The only limit is memory but there you have the same limits as any other "rational number". You seem t be splitting hairs now you have lost. – Martin York Mar 13 '13 at 15:14
  • 1
    @EmilioGaravaglia: When people change their argument move onto more obscure excuses its a sign they are grabbing at straws to prove a point they already lost. You were wrong. Sorry. It happens. – Martin York Mar 14 '13 at 21:51
  • 1
    Please, at least understand we are both saying the same thing ... Revise the SEMATICS of ALL OF OUR POST, and forgot whatever "longest piss contest" you have in your mind. Just wash up and open it. I'm NOT against you. There is only one argument here: and EXACT DECIMAL DATA TYPE (the one the OP posted in its title), that's not physically sustainable.... – Emilio Garavaglia Mar 15 '13 at 07:58
  • 1
    ... Then there are "approximation" that allow exactness to exist in given compact ranges (integers of whatever size, but cannot represent non-integer expressions) or approximation finest or widely distributed depending on how much precision is available. And this happes in statically "scaled" integers, dynamically scaled integers (long name for fractions) or floating point of whatever species. And they are all what you talked about (and whoever can talk about, since is all what the physics can give us) – Emilio Garavaglia Mar 15 '13 at 07:58
  • 1
    You can use as many bits you want, but that doesn't make your number "exact" for whatever calculation. It just make it more precise and increase the probability an exact representation for values of particular interest in a given field is matched. But no more than this. There is nothing to "win" or "loose" here. Just be aware of the limitation of our tools. – Emilio Garavaglia Mar 15 '13 at 08:02
  • 4
    @EmilioGaravaglia: After re-reading. You seem to be confusing exact infinite (exact) and arbitrary (exact). The whole point of the library is that you never loose precision from your inputs. The internal representations used is supposed to maintain a representation that is at least as precise as the input. Any operation that would result in a loss of representation like `1/3` is deferred so it can be cancelled out later. Rational numbers (like `pi` and `e`) are not converted to a decimal representation (just like when you do maths by hand). – Martin York Mar 16 '13 at 16:09
  • 2
    @EmilioGaravaglia: So any mathematics is done at the exact precision you need. Of course there are limits computers have a finite memory so you could potentially use it all up fine (but you crash long before that happens). But effectively you have **exact** arbitrary precision because you don't loose any. Which is better than infinite as that is a meaningless comparison. – Martin York Mar 16 '13 at 16:10
  • @LokiAstari You probably meant **ir**rational numbers instead of rational. In any case, not converting such numbers to a decimal representation isn't a strong argument. Canceling `pi` and `e` isn't always possible. In fact, it isn't in most non-trivial situations. How will you calculate `pi*e/sqrt(2)`? Ultimately, in most cases there is a need in a numeric answer rather than symbolic. – SomeWittyUsername Aug 30 '16 at 17:19
  • @SomeWittyUsername: Why can the answer not be `pi*e/sqrt(2)`. It has the same meaning. – Martin York Aug 30 '16 at 20:40
  • @LokiAstari Of course it has the same meaning. But we're talking about software and not about math. The result of this computation in over 99% of usecases will be fed into some other module to use it or to perform further computations. And this other module probably won't (and shouldn't) have the ability to handle symbolic math. – SomeWittyUsername Aug 30 '16 at 21:41
  • @SomeWittyUsername: Sure if you are printing out or using it to draw at some point you have to convert it to a numbering system that will have a finite representation and that's were you error will be introduced. The point of arbitrary precision libraries though is that you don't need to do that rounding or get the imprecision until exactly that point where you need the number for display. Until that point it can be represented exactly. – Martin York Aug 30 '16 at 22:06
  • @LokiAstari That may be true for simple one-step calculations but it won't hold for complex multi-step calculations where one step feeds the next one. Consider, for example, computing the integral of irrational function as an intermediate result. Or dealing with expressions that don't have a closed form. – SomeWittyUsername Aug 30 '16 at 22:35
  • @SomeWittyUsername I think it holds more true for the more complex operations. You don't tend to write software with multiple mathematical library you tend to pick one and use it for all your needs. Only converting to the final representation as the absolute final step. – Martin York Aug 31 '16 at 00:50
5

If you are looking for data type supporting money / currency then try this: https://github.com/vpiotr/decimal_for_cpp

(it's header-only solution)

Piotr
  • 211
  • 3
  • 2
4

There will be always some precision. On any computer in any number representation there will be always numbers which can be represented accurately, and other numbers which can't.

  • Computers use a base 2 system. Numbers such as 0.5 (2^-1), 0.125 (2^-3), 0.325 (2^-2 + 2^-3) will be represented accurately (0.1, 0.001, 0.011 for the above cases).

  • In a base 3 system those numbers cannot be represented accurately (half would be 0.111111...), but other numbers can be accurate (e.g. 2/3 would be 0.2)

  • Even in human base 10 system there are numbers which can't be represented accurately, for example 1/3.

  • You can use rational number representation and all the above will be accurate (1/2, 1/3, 3/8 etc.) but there will be always some irrational numbers too. You are also practically limited by the sizes of the integers of this representation.

  • For every non-representable number you can extend the representation to include it explicitly. (e.g. compare rational numbers and a representation a/b + c/d*sqrt(2)), but there will be always more numbers which still cannot be represented accurately. There is a mathematical proof that says so.

So - let me ask you this: what exactly do you need? Maybe precise computation on decimal-based numbers, e.g. in some monetary calculation?

CygnusX1
  • 19,236
  • 3
  • 55
  • 100
3

What you're asking is anti-physics.

What phyton (and C++ as well) do is cut off the inaccuracy by rounding the result at the time to print it out, by reducing the number of significant digits:

double x = 2.5;
x += 2.5;
std::cout << x << std::endl;

just makes x to be printed with 6 decimal digit precision (while x itself has more than 12), and will be rounded as 5, cutting away the imprecision.

Alternatives are not using floating point at all, and implement data types that do just integer "scaled" arithmetic: 25/10 + 25/10 = 50/10;

Note, however, that this will reduce the upper limit represented by each integer type. The gain in precision (and exactness) will result in a faster reach to overflow.

Rational arithmetic is also possible (each number is represented by a "numarator" and a "denominator"), with no precision loss against divisions, (that -in fact- are not done unless exact) but again, with increasing values as the number of operation grows (the less "rational" is the number, the bigger are the numerator and denominator) with greater risk of overflow.

In other word the fact a finite number of bits is used (no matter how organized) will always result in a loss you have to pay on the side of small on on the side of big numbers.

Emilio Garavaglia
  • 18,858
  • 2
  • 41
  • 60
0

I presume you are talking about the Binary Calculator in PHP. No, there isn't one in the C runtime or STL. But you can write your own if you are so inclined.

Here is a C++ version of BCMath compiled using Facebook's HipHop for PHP: http://fossies.org/dox/facebook-hiphop-php-cf9b612/dir_2abbe3fda61b755422f6c6bae0a5444a.html

Hawk Eye
  • 126
  • 1
  • 7
-3

Being a higher level language PHP just cuts off what you call "inaccuracy" but it's certainly there. In C/C++ you can achieve similar effect by casting the result to integer type.

SomeWittyUsername
  • 17,203
  • 3
  • 34
  • 78
  • If precision is such concern, casting to an integer would be a very stupid thing to do. It may work fine in the case of the result 4.999999999978325 but it will be a very bad call for anything that should not be rounded to a integer. – dtech Mar 10 '13 at 07:39
  • @ddriver Well, how do you think PHP decides to represent the result of 2.5+2.5 as 5? If it shouldn't be rounded, don't round it, sorry for tautology. – SomeWittyUsername Mar 10 '13 at 07:47