boost::multiprecision::pow with two cpp_int values - c++

Is there a way to use boost::multiprecision::pow with two cpp_int values as the parameters? All I can find in the documentation has the parameters of type cpp_int for the base and int for the exponent. This seems very limiting.

Comment: How is that limiting? Will you be raising to powers above MAXINT? How?
Q:
What do you mean 'how'? Isn't the point of multiprecision libraries to handle enormous numbers like this?
No. Enormous numbers like this rarely make any sense at lossless precisions.
Lets say we start out with a reasonably small number, like 10. The smallest exponent that doesn't fit in a 64-bit integer would be 2^64. So, the number is 10^(2^64), which is roughly 18446744073709551617 decimal digits
≈ 1.84467×10^19 decimal digits.
To print that you'd need paper weighing roughly 1.4757×10^11 metric tons, assuming 5,000 digits per 80g page. That's roughly the equivalent of total biomass on Earth (≈ 8×10^13 kg).
Now, of course you're not silly, and you won't print it! You only need to fit it in RAM, which is why you have started crowd funding for your 7.6598 exabytes of RAM. Not to mention the power supply for it, because powering that for one hour will cost take around 7 gigawatt hours, which is comparable to half the energy yield of Little Boy nuclear bomb.
What Can You Do
Boost Multiprecision does allow you to use exact and lossless representation of huge integral number, but the resources of your systems limit the total capacity.
As shown, exponents exceeding 64 bit integers are not sensible for these types.
You can, of course, use a decimal/binary floating point representation at arbitrary precision (still honouring the constraints of physics and economics, of course), like boost::multiprecision::mpf_float_1000.

You may use boost::multiprecision::float and corresponding boost::multi precision::pow implementations.

Related

Why cents for std::put_money()?

I'm wondering why the std::put_money() function accepts cents instead of dollars. Also looking at the definition on cppreference, it does not say what the input number should be.
Is it true that whatever the currency we have to use a decimal number at the lowest possible decimal value of said currency? (i.e. so * 1.0, * 100.0, or * 1000.0 as the case may be?) Because that seems to incorporate knowledge of the currency opposed to the current locale...
The general idea is that you don't want to use floating point with currency, because values with a finite number of decimal digits can be periodic in binary, and given that floating point values have finite precision this leads to surprises when summing them; the usual example is
#include <stdio.h>
int main(void) {
double v = 0.;
for(int i=0; i<10; ++i) v+=0.1;
printf("%0.18g\n", v-1.0f);
return 0;
}
which prints -1.11022302462515654e-16.
A simple approach to deal with the problem is to use integral values for "the smallest non-fractional units of the currency" (thanks #Justin for the quote); this makes sure that when the user inputs $ 0.10 it's exactly represented, and does not lead to any rounding surprise, at least as long as we are dealing with values where exact precision is expected.
This is fine and explains the cents, but why long double and not some integral type? Here I'm speculating, but I see two reasonable motivations:
fractional amounts of currency are something that exists, typically for unitary prices (e.g. the price per liter of gasoline); the precision there is generally less of an issue - you are going to multiply it by another floating point value anyway - but you want to be able to read such values;
but most importantly, historically floating point values had the best precision over a wide spectrum of platforms, even for integral values. long long (guaranteed to be at least 64 bit) is a recent addition to the standard, and long was generally 32 bit wide: it would have capped monetary values to a meager ~21 million dollars.
OTOH, even a plain double on most platforms has a 53 digits mantissa, which means that it can represent exactly integral values up to 9007199254740991 - so, something like 90 thousand billion dollars; that's good enough to represent exactly the US public debt down to cents, so it's probably precise enough for pretty much anything else. They probably chose long double as "the biggest hammer they can throw at the problem" (even if nowadays it's generally as big as a plain double).
Because that seems to incorporate knowledge of the currency opposed to the current locale...
Yes and no; I think that the idea was that, as long as you use the relevant locale facets both for input and for output, you simply shouldn't really care - the library should do the conversions for you, and you just work with numbers whose exact magnitude shouldn't really matter to you.
That's the theory; but as said in the comments, C and C++ locales are a badly designed piece of software, with an overly complicated design which however falls short when tested for real-world usage.
Honestly, I would never use this stuff "for real":
you can never be sure of how updated the standard library is, how broken it is (I once had VC++ not being able to do a roundtrip of Italian-localized numbers), if it actually supports the currencies you care about.
you do need to care about what is its idea of "smallest non-fractional unit of the currency" if you need to talk with anything besides textual IO in the format expected by the library - say, you have to get the price of a stock from a web service, or if you have built-in data to combine with the user input;
same for serialization in a machine readable format; you don't want to expose yourself to the vagaries of your C runtime and of OS configuration when storing the user data, especially if they are to be exchanged with other applications, especially if said applications run on a different C runtime (it may even be your own application compiled for a different operating system!) or a different language.

How do I find the largest integer fully supported by hardware arithmetics?

I am implementing a BigInt class that must support arbitrary-precision operations on integers.
Quote from "The Algorithm Design Manual" by S.Skiena:
What base should I do [editor's note: arbitrary-precision] arithmetic in? - It is perhaps simplest to implement your own high-precision arithmetic package in decimal, and thus represent each integer as a string of base-10 digits. However, it is far more efficient to use a higher base, ideally equal to the square root of the largest integer supported fully by hardware arithmetic.
How do I find the largest integer supported fully by hardware arithmetic? If I understand correctly, being my machine an x64 based PC, the largest integer supported should be 2^64 (http://en.wikipedia.org/wiki/X86-64 - Architectural features: 64-bit integer capability), so I should use base 2^32, but is there a way in c++ to get this size programmatically so I can typedef my base_type to it?
You might be searching for std::uintmax_t and std::intmax_t.
static_cast<unsigned>(-1) is the max int. e.g. all bits set to 1 Is that what you are looking for ?
You can also use std::numeric_limits<unsigned>::max() or UINT_MAX, and all of these will yield the same result. and what these values tell is the maximum capacity of unsigned type. e.g. the maximum value that can be stored into unsigned type.
int (and, by extension, unsigned int) is the "natural" size for the architecture. So a type that has half the bits of an int should work reasonably well. Beyond that, you really need to configure for the particular hardware; the type of the storage unit and the type of the calculation unit should be typedefs in a header and their type selected to match the particular processor. Typically you'd make this selection after running some speed tests.
INT_MAX doesn't help here; it tells you the largest value that can be stored in an int, which may or may not be the largest value that the hardware can support directly. Similarly, INTMAX_MAX is no help, either; it tells you the largest value that can be stored as an integral type, but doesn't tell you whether operations on such a value can be done in hardware or require software emulation.
Back in the olden days, the rule of thumb was that operations on ints were done directly in hardware, and operations on longs were done as multiple integer operations, so operations on longs were much slower than operations on ints. That's no longer a good rule of thumb.
Things are not so black and white. There are MAY issues here, and you may have other things worth considering. I've now written two variable precision tools (in MATLAB, VPI and HPF) and I've chosen different approaches in each. It also matters whether you are writing an integer form or a high precision floating point form.
The difference is, integers can grow without bound in the number of digits. But if you are doing a floating point implementation with a user specified number of digits, you always know the number of digits in the mantissa. This is fixed.
First of all, it is simplest to use a single integer for each decimal digit. This makes many things work nicely, so I/O is easy. It is a bit inefficient in terms of storage though. Adds and subtracts are easy though. And if you use integers for each digit, then multiplies are even easy. In MATLAB for example, conv is pretty fast, though it is still O(n^2). I think gmp uses an fft multiply, so faster yet.
But assuming you use a basic conv multiply, then you need to worry about overflows for numbers with a huge number of digits. For example, suppose I store decimal digits as 8 bit signed integers. Using conv, followed by carries, I can do a multiply. For example, suppose I have the number 9999.
N = repmat(9,1,4)
N =
9 9 9 9
conv(N,N)
ans =
81 162 243 324 243 162 81
Thus even to form the product 9999*9999, I'd need to be careful as the digits will overflow an 8 bit signed integer. If I'm using 16 bit integers to accumulate the convolution products, then a multiply between a pair of 1000 digits integers can cause an overflow.
N = repmat(9,1,1000);
max(conv(N,N))
ans =
81000
So if you are worried about the possibility of millions of digits, you need to watch out.
One alternative is to use what I call migits, essentially working in a higher base than 10. Thus by using base 1000000 and doubles to store the elements, I can store 6 decimal digits per element. A convolution will still cause overflows for larger numbers though.
N = repmat(999999,1,10000);
log2(max(conv(N,N)))
ans =
53.151
Thus a convolution between two sets of base 1000000 migits that are 10000 migits in length (60000 decimal digits) will overflow the point where a double cannot represent an integer exactly.
So again, if you will use numbers with millions of digits, beware. A nice thing about the use of a higher base of migits with a convolution based multiply is since the conv operation is O(n^2), then going from base 10 to base 100 gives you a 4-1 speedup. Going to base 1000 yields a 9-1 speedup in the convolutions.
Finally, the use of a base other than 10 as migits makes it logical to implement guard digits (for floats.) In floating point arithmetic, you should never trust the least significant bits of a computation, so it makes sense to keep a few digits hidden in the shadows. So when I wrote my HPF tool, I gave the user control of how many digits would be carried along. This is not an issue for integers of course.
There are many other issues. I discuss them in the docs carried with those tools.

If float and double are not accurate, how do banks perform accurate calculations involving money?

Currently learning C++ and this has just occurred to me. I'm just curious about this as I'm about do develop a simple bank program. I'll be using double for calculating dollars/interest rate etc., but there are some tiny differences between computer calculations and human calculations.
I imagine that those extra .pennies in the real world can make all the difference!
In many cases, financial calculations are done using fixed-point arithmetic instead of floating point.
For example, the .NET Decimal type, or the VB6 Currency type. These are basically just integer types, where everyone has agreed that the units are some fraction of a cent, like $.0001.
And yes, some rounding has to occur, but it is done very systematically. Usually the rounding rules are somewhere deep in the fine print of your contract (the interest rate is x%, compounded every T, rounded up to the nearest penny, but not less than $y every statement period).
The range of a 8 byte long long is: -9223372036854775808 max: 9223372036854775807 do everything as thousands of a cent/penny and you still can handle numbers up to the trillions of dollars/pounds/whatever.
It depends on the application. All calculations with decimals will
require rounding when you output them as dollars and cents (or whatever
the local currency is): the base price of an article may only have two
digits after the decimal, but when you add on sales tax or VAT, there
will be more, and if you need to calculate interest on an investment,
there will be more.
Generally, using double results in the most accurate results,
however... if your software is being used for some sort of bookkeeping
required by law (e.g. for tax purposes), you may be required to follow
standard accepted rounding practices, and these are based on decimal
arithmetic, not binary, hexadecimal or octal (which are the usual bases
for floating point—binary is universal on everything but
mainframes). In such cases, you'll need to use some sort of Decimal
class, which ensures the correct rounding. For other uses (e.g. risk
analysis), double is fine.
Just because a number is not an integer does not mean that it cannot be calculated exactly. Consider that a dollars-and-cents value is an integer if one counts the number of pennies (cents), so it is a simple matter for a fixed-point library using two decimals of precision to simply multiply each number by 100, perform the calculation as an integer, and then divide by 100 again.

Is it possble to combine number of float values into one float value and extract the values when needed?

Am working on an algorithm for an iPhone app, where the data i need to keep in memory is exceeding the limit, so is it possible to represent number of float numbers as one float value and retrieve those value when i need.
For instance:
float array[4];
array[0]=0.12324;
array[1]=0.56732;
array[2]=0.86555;
array[3]=0.34545;
float combinedvalue=?
Not in general, no. You can't store 4N bits of information in only N bits.
If there's some patten in your numbers, then you might find a scheme. For example, if all your numbers are of similar value, you could potentially store only the differences between the numbers in lower precision.
However, this kind of thing is difficult, and limited.
If those numbers are exactly 5 digits each, you can treat them as ints by multiplying with 100000. Then you'll need 17 bits for each number, 68 bits in total, which (with some bit-shifting) takes up 9 bytes. Does that help, 9 bytes instead of 16?
Please note that the implementation of your algorithm will also take up memory!
What you are requiring could be accomplished in several different ways.
For instance, in c++ you generally have single precision floats (4 bytes) as the smallest precision available, though I wouldn't be surprised if there are other packages that handle smaller precision floating point values.
Therefore, if you are using double precision floating point values and can get by with less precision then you can switch to a smaller precision.
Now, depending on your range of values you want to store, you might be able to use a fixed-point representation as well, but you will need to be familiar with the nuances of bit shifting and masking, etc. But, another added benefit of this approach is that it could make your program run faster since fixed-point (integer) arithmetic is much faster than floating-point arithmetic.
The choice of options depends on your data you need to store and how comfortable you are with lower level binary arithmetic.

Large doubles/float/numbers

Say I have a huge floating number, say a trillion decimal places out. Obviously a long double can't hold this. Let's also assume I have a computer with more than enough memory to hold it. How do you do something like this?
You need arbitrary-precision arithmetic.
Arbitrary-precision math.
It's easy to say "arbitrary precision arithmetic" (or something similar), but I think it's worth adding that it's difficult to conceive of ways to put numbers anywhere close to this size to use.
Just for example: the current estimates of the size of the universe are somewhere in the vicinity of 150-200 billion light years. At the opposite end of the spectrum, the diameter of a single electron is estimated at a little less than 1 atometer. 1 light year is roughly 9.46x1015 meters (for simplicity, we'll treat it as 1016 meters).
So, let's take 1 atometer as our unit, and figure out the size of number for the diameter of the universe in that unit. 1018 units/meter * 1016 meters/light year * 1011 light years/universe diameter = about a 45 digit number to express the diameter of the universe in units of roughly the diameter of an electron.
Even if we went the next step, and expressed it in terms of the theorized size of a superstring, and added a few extra digits just in case the current estimates are off by a couple orders of magnitude, we'd still end up with a number around 65 digits or so.
This means, for example, that if we knew the diameter of the universe to the size of a single superstring, and we wanted to compute something like volume of the universe in terms of superstring diameters, our largest intermediate result would be something like 600-700 digits or so.
Consider another salient point: if you were to program a 64-bit computer running at, say, 10 GHz to do nothing but count -- increment a register once per clock cycle -- it would take roughly 1400 years for it to just cycle through the 64-bit numbers so it wrapped around to 0 again.
The bottom line is that it's incredibly difficult to come up with excuses (much less real reasons) to carry out calculations to anywhere close to millions, billions/milliards or trillions/billions of digits. The universe isn't that big, doesn't contain that many atoms, etc.
Sounds like what logarithms were invented for.
Without knowing what you intend to do with the number, it's impossible to accurately say how to represent it.