1

I have written a program which performs some simple arithmetic with very large numbers. I succeeded in using mpz_int and mpf_float from the boost multiprecision libraries, but found that i needed more precision to achieve my purpose. I have been trying to use the mpfr library to define a float with greater precision. I was able to get my code to compile but now receive the runtime error libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl >: The string “1572…[4000 digits]…00.328” could not be interpreted as a valid integer.

I have a feeling that it is my attempt to convert the mpfr_float I created to an integer that is causing the problem. I initialize the float from a string which is an integer, and do some division before attempting to round down and convert to an integer. Here is my typedef:

typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<4680> > bloatfloat;

my declaration:

bloatfloat seed(“4716…etc.”);

and my attempted conversion:

boost::multiprecision::mpz_int seedint = seed.convert_to<boost::multiprecision::mpz_int>();

If someone could help me just to accomplish this conversion and avoid the runtime error, I would be very grateful. I think though that the source of my confusion may lie deeper than that, so I’d like to explain a little about my project, and see if anyone can tell me if there is anything I am doing which is more fundamentally wrong.

I am trying to create pages of text which appear random but are constructed out of a predictable pseudo-random function. So that if someone inputs 1, then 2, then 3, they would notice no pattern between the three pages of text, but entering any of those numbers gives the same text each time. I am trying to create all possibilities of a page of 29 characters 3200 times, or 29^3200 possibilities (about 10^4680).

I am using a halton sequence to generate the pseudo-random quality, and multiplying the result by 29^3200.

Here is my halton sequence:

while (input>0) {
    denominator *=3;
    numerator = numerator * 3 + (input%3);
    input = input/3;
}

I then do a base conversion from the resulting number to base-29 to get a page of text. Initially I used mpz_int for 29^3200 (initialized from a string) - but I found that this would produce repeating patterns. depending on what the denominator from the halton sequence was. for example, input which produced the denominator 243 would produce a page of text with the same 162 characters repeating from 3200 characters, just in a different position.

Here is the base conversion segment of my program:

boost::multiprecision::mpz_int seedint(seed); //converts from mpf_float
boost::multiprecision::mpz_int holder = 0;
std::string permuda [29] = {" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ",", "."};
std::string book = "";
holder = seedint%29;
int conversion = holder.convert_to<int>();
book = permuda[conversion];
while (seedint>=29) {
    seedint = seedint/29;
    holder = seedint%29;
    conversion = holder.convert_to<int>();
    book.insert(0,permuda[conversion]);
}
std::cout << book << "\n";

I don’t have a good enough sense of the mathematics to understand why this repetition happened, but on a hunch I changed to a float. I found that this did much better - the patterns were much shorter and would only begin to appear at the beginning of the output string (representing the higher values), but ultimately they were still there and recognizable. I found that mpf_float worked better than mpf_float_1000, and both of them were much better than mpz_int in terms of producing more random-seeming results.

As i mentioned before, my surface question is simply: how do i avoid this runtime error? But my deeper concern is: a) why are these patterns appearing? am i correct that floats with greater precision will eliminate these repeating strings? and b) if so, is mpfr_float the best data type? what degree of precision should i give it? c) if not, what data type should i use?

I am very thankful to anyone who can answer any of these questions.

---EDIT---

I solved the problem I was having simply by sticking with mpf_float, using 29^3280 as a seed, and cutting off the last 80 characters, which were the repetitious ones. I'm still curious about fixed and variable precision, though. When I tried to define a fixed precision gmp_float with a higher template parameter I got much worse results. What exactly is fixed and variable precision and why does it produce such results?

Jonathan Basile
  • 649
  • 1
  • 10
  • 20
  • There seems to be a moderate degree of X/Y problem involved here. In one by-clause we can sort-of glean that you're trying to generate unique indices into a huge integer domain using Halton series pseudo random thing. Perhaps you would prefer to ask a question about that :) – sehe Apr 09 '15 at 22:29
  • Have you considered the rational types? – sehe Apr 09 '15 at 22:30
  • Well, i tried to give a description of the background of my project to do my best to evade an XY problem - do you think I would lose less data if i worked with rationals as opposed to ints or floats? I'm still trying to wrap my head around fixed and variable precision, and how they're impacting the results im getting – Jonathan Basile Apr 10 '15 at 01:00
  • Well, as posed, the whole reference to Halton series is very much irrelevant. I also don't feel that whether using rationals is going to reduce memory consumption is relevant until we know what you're trying achieve. FWIW it's a design smell if you have to cut of large chunks of the result just to make things "random enough". Something tells me the approach is not suited to the problem, or the application of it is flawed. But the question is not about that ... :) – sehe Apr 10 '15 at 06:25

1 Answers1

1

If you want rounding, specify rounding:

seed = floor(seed); // round down

Live On Coliru

#include <boost/multiprecision/gmp.hpp>
#include <boost/multiprecision/mpfr.hpp>
#include <iostream>

namespace bmp = boost::multiprecision;

int main() {

    typedef bmp::number<bmp::mpfr_float_backend<4680> > bloatfloat;

    bloatfloat seed(
            "721201701982919384816919444629094602157676451009178493145697699033198799100795129"
            "461065252402772377100211702907679573288486469509354650292261514983089857585626889"
            "148299172516026989131041249763387900393649171847047199176208319323777423754787299"
            "899902453021655169650961976509782411649465051858878446823598416509136950922118426"
            "589618889559294511223766379025710403342501323543498101455439622897437844155269586"
            "993049821123424147085390549823755712672917476850165059107549100936676307424188564"
            "036471526370341311363147513165267081098820842568364867108467458147148215066631620"
            "521442723811840296249653692907217273194142954467472723479281126853419846351214589"
            "919458685154151951719281841322812833916704023062806547205146388218774938812715995"
            "71277364984644114752231471655539342153193201013.261");

    seed = floor(seed); // round down
    auto seedint = seed.convert_to<bmp::mpz_int>();

    std::cout << seedint;
}

Prints

72120170198291938481691944462909460215767645100917849314569769903319879910079512946106525240277237710021170290767957328848646950935465029226151498308985758562688914829917251602698913104124976338790039364917184704719917620831932377742375478729989990245302165516965096197650978241164946505185887844682359841650913695092211842658961888955929451122376637902571040334250132354349810145543962289743784415526958699304982112342414708539054982375571267291747685016505910754910093667630742418856403647152637034131136314751316526708109882084256836486710846745814714821506663162052144272381184029624965369290721727319414295446747272347928112685341984635121458991945868515415195171928184132281283391670402306280654720514638821877493881271599571277364984644114752231471655539342153193201013

sehe
  • 374,641
  • 47
  • 450
  • 633