Anonymous Anonymous - 1 month ago 34
C++ Question

Convert Boost Multi-precision Float to String maintaining precision

How can I convert from an Boost's multiprecision float to a string without it being truncated?

I have the following code:

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

int main() {
const int precision = 100;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<precision> > absFloat;

std::cout << "Iterations: ";
int iterations;
std::cin >> iterations;

absFloat wnew = 0.0, x;

std::cout << "W(x), x = ";
std::cin >> x;

std::cout << std::setprecision(precision);

std::string firstStr, secondStr;

for(int i = 0; i <= iterations; i++){
firstStr = boost::lexical_cast<std::string>(wnew);
wnew = ((wnew * wnew) + x * exp(-wnew))/(1+wnew);
secondStr = boost::lexical_cast<std::string>(wnew);
if(firstStr == secondStr)
break;
std::cout << "\n" << i << " - " << wnew << "\n";
}

std::cout << "\n" << firstStr << std::endl;
std::cout << secondStr << std::endl;

return 0;
}


What it actually does is not very crucial as far as this question is concerned, but simply put it approximates the value of the Lambert W function using a simplified version of the Newton–Raphson method.

The code I am asking about is inside the
for
loop:

for(int i = 0; i <= iterations; i++){
firstStr = boost::lexical_cast<std::string>(wnew);
wnew = ((wnew * wnew) + x * exp(-wnew))/(1+wnew);
secondStr = boost::lexical_cast<std::string>(wnew);
if(firstStr == secondStr)
break;
std::cout << "\n" << i << " - " << wnew << "\n";
}


Here I am converting from an arbitrary-precision floating-point number (in this case it has 100 decimals
const int precision = 100
) to a string. The value of
precision
will be manually changed constantly.

I convert the value of
wnew
to a string before and after calculations, then compare the two strings. If they are identical, the
for
loop is broken. This is not the result I am getting.

Here is the result with
iterations
set to
20
and
x
set to
1
:

Iterations: 20
W(x), x = 1

0 - 1

1 - 0.6839397205857211607977618850807304337229055655158839172539184008487307478724499016785736371729598219

2 - 0.5774544771544497158879277307209708744246953720136943334618725831739970553254359545244940341535829055

3 - 0.5672297377301170424199788873305659381989740529912345334258918256943726362413406459666277736815827773

4 - 0.5671432965302959290104061393322652388244468110017561469052367139960666960291476041675058924102131759

0.567143
0.567143

RUN SUCCESSFUL (total time: 1s)


As you can see, the strings are the same after the 4th iteration. But in fact the numbers are the same after the 8th iteration! Here is the rest of the output without the if statement break:

Iterations: 20
W(x), x = 1

0 - 1

1 - 0.6839397205857211607977618850807304337229055655158839172539184008487307478724499016785736371729598219

2 - 0.5774544771544497158879277307209708744246953720136943334618725831739970553254359545244940341535829055

3 - 0.5672297377301170424199788873305659381989740529912345334258918256943726362413406459666277736815827773

4 - 0.5671432965302959290104061393322652388244468110017561469052367139960666960291476041675058924102131759

5 - 0.5671432904097839036821986273638501915396349920558000709178381348786164164929847042875694697488581049

6 - 0.5671432904097838729999686622103563208086217342023287565768851248326011789240991181028762582526321268

7 - 0.5671432904097838729999686622103555497538157871865125081351310792235327403215041862450323133272582057

8 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

9 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

10 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

11 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

12 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

13 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

14 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

15 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

16 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

17 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

18 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

19 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

20 - 0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946

0.567143
0.567143

RUN SUCCESSFUL (total time: 1s)


Why is the multi-precision float being truncated when being converted to a string? How can I convert from an Boost's multiprecision float to a string without it being truncated?

Answer

Found the solution on my own, I was over-complicating it. To convert from a Boost multiprecision float to a string is actually pretty simple:

for(int i = 0; i <= iterations; i++){
    std::string firstStr = wnew.convert_to<std::string>();
    wnew = ((wnew * wnew) + x * exp(-wnew))/(1+wnew);
    std::string secondStr = wnew.convert_to<std::string();
    if(firstStr == secondStr)
        break;
    std::cout << "\n" << i << " - " << wnew << "\n";
}

Using convert_to also revealed the reason why it was not stopping after the 8th iteration. The numbers are actually longer than they were being displayed as, so after each iteration they were all different.