c++ random number between two integers using WELL512 - c++

I see that this question may have been answered here: Random using WELL512
However, it's not quite user friendly and doesn't provide an example how to use it in a 'real world' piece of code.
Here is what I currently have:
#define m (unsigned long)2147483647
#define q (unsigned long)127773
#define a (unsigned int)16807
#define r (unsigned int)2836
static unsigned long seed;
void x_srandom(unsigned long initial_seed);
unsigned long x_random(void);
void x_srandom(unsigned long initial_seed)
{
seed = initial_seed;
}
unsigned long x_random(void)
{
int lo, hi, test;
hi = (seed / q);
lo = (seed % q);
test = (a * lo - r * hi);
if (test > 0)
seed = test;
else
seed = (test + m);
return (seed);
}
int RANDOM(int from, int to)
{
if (from > to)
{
int tmp = from;
from = to;
to = tmp;
}
return ((x_random() % (to - from + 1)) + from);
}
// Real world function using RANDOM()
void testFunction()
{
printf("A random number between 1 and 1000 is %d \r\n", RANDOM(1, 1000));
printf("A random number between 36 and 100 is %d \r\n", RANDOM(36, 100));
printf("A random number between 1 and 2147483647 is %d \r\n", RANDOM(1, 2147483647));
printf("A random number between 1 and 5 is %d \r\n", RANDOM(1, 5));
}
The above example shows everything you need to know to implement it.
I would like to use WELL512 to determine my random numbers instead of the way in which I currently am, put in a way as exampled above.

It is really time to move away from using % for generating a distribution.
To me you should use WELL512 as a uniform random number generator (just like mt19937 in the standard library). You wrap it in a class that exposes a typedef (or using) for result_type. In your case that would probably be unsigned long. Then you need two constexpr for min() and max(). That would be 0 and ULONG_MAX. Finally you need to expose operator() that returns a single unsigned long.
After that you use the features in <random> together with your engine.
class well512 {
public:
typedef unsigned long result_type;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return ULONG_MAX; }
result_type operator()() { /* return some value from the underlying well512 implementation */ }
};
int main()
{
well512 engine();
std::uniform_int_distribution<> dist { 1, 5 };
for (int i = 0; i != 10; ++i)
{
std::cout << dist(engine) << std::endl;
}
return 0;
}

Here is a complete example. It does not have all the bells and whistles you may want. E.g. there is no default constructor, or a constructor from a single word. I leave that as an exercise.
#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <numeric>
#include <ostream>
#include <random>
#include <vector>
class seed_seq
{
public:
template <typename InputIterator>
seed_seq(InputIterator first, InputIterator last)
{
for (; first != last; ++first)
{
v.push_back(*first);
}
}
template <typename RandomAccessIterator>
void generate(RandomAccessIterator first, RandomAccessIterator last)
{
std::vector<unsigned int>::size_type i = 0;
for (; first != last; ++first)
{
*first = v[i];
if (++i == v.size()){ i = 0; }
}
}
private:
std::vector<unsigned int> v;
};
class well512
{
public:
using result_type = unsigned int;
static result_type min() { return 0; }
static result_type max() { return std::numeric_limits<std::uint32_t>::max(); }
static const unsigned int state_size = 16;
explicit well512(seed_seq& sequence) : index(0)
{ sequence.generate(std::begin(state), std::end(state)); }
result_type operator()()
{
std::uint32_t z0 = state[(index + 15) & 0x0fU];
std::uint32_t z1 = xsl(16, state[index]) ^ xsl(15, state[(index + 13) & 0x0fU]);
std::uint32_t z2 = xsr(11, state[(index + 9) & 0x0fU]);
state[index] = z1 ^ z2;
std::uint32_t t = xslm(5, 0xda442d24U, state[index]);
index = (index + state_size - 1) & 0x0fU;
state[index] = xsl(2, z0) ^ xsl(18, z1) ^ (z2 << 28) ^ t;
return state[index];
}
private:
// xor-shift-right
std::uint32_t xsr(unsigned int shift, std::uint32_t value)
{ return value ^ (value >> shift); }
// xor-shift-left
std::uint32_t xsl(unsigned int shift, std::uint32_t value)
{ return value ^ (value << shift); }
// xor-shift-left and mask
std::uint32_t xslm(unsigned int shift, std::uint32_t mask, std::uint32_t value)
{ return value ^ ((value << shift) & mask); }
unsigned int index;
std::array<std::uint32_t, state_size> state;
};
int main()
{
// Use a random device to generate 16 random words used as seed for the well512 engine
std::random_device rd;
std::vector<well512::result_type> seed_data;
std::generate_n(std::back_inserter(seed_data), well512::state_size, std::ref(rd));
seed_seq sequence(std::begin(seed_data), std::end(seed_data));
// Create a well512 engine
well512 engine(sequence);
// Now apply it like any other random engine in C++11
std::uniform_int_distribution<> dist{ 1, 6 };
auto rand = std::function <int()> { std::bind(std::ref(dist), std::ref(engine)) };
// Print out some random numbers between 1 and 6 (simulating throwing a dice)
const int n = 100;
std::generate_n(std::ostream_iterator<int>(std::cout, " "), n, rand);
std::cout << std::endl;
return 0;
}

Like this user515430 ?
#define m (unsigned long)2147483647
#define W 32
#define R 16
#define P 0
#define M1 13
#define M2 9
#define M3 5
#define MAT0POS(t,v) (v^(v>>t))
#define MAT0NEG(t,v) (v^(v<<(-(t))))
#define MAT3NEG(t,v) (v<<(-(t)))
#define MAT4NEG(t,b,v) (v ^ ((v<<(-(t))) & b))
#define V0 STATE[state_i ]
#define VM1 STATE[(state_i+M1) & 0x0000000fU]
#define VM2 STATE[(state_i+M2) & 0x0000000fU]
#define VM3 STATE[(state_i+M3) & 0x0000000fU]
#define VRm1 STATE[(state_i+15) & 0x0000000fU]
#define VRm2 STATE[(state_i+14) & 0x0000000fU]
#define newV0 STATE[(state_i+15) & 0x0000000fU]
#define newV1 STATE[state_i ]
#define newVRm1 STATE[(state_i+14) & 0x0000000fU]
#define FACT 2.32830643653869628906e-10
static unsigned int state_i = 0;
static unsigned int STATE[R];
static unsigned int z0, z1, z2;
void InitWELLRNG512a(unsigned int *init){
int j;
state_i = 0;
for (j = 0; j < R; j++)
STATE[j] = init[j];
}
double WELLRNG512a(void){
z0 = VRm1;
z1 = MAT0NEG(-16, V0) ^ MAT0NEG(-15, VM1);
z2 = MAT0POS(11, VM2);
newV1 = z1 ^ z2;
newV0 = MAT0NEG(-2, z0) ^ MAT0NEG(-18, z1) ^ MAT3NEG(-28, z2) ^ MAT4NEG(-5, 0xda442d24U, newV1);
state_i = (state_i + 15) & 0x0000000fU;
return ((double)STATE[state_i]) * FACT;
}
int RANDOM(int from, int to)
{
if (from > to)
{
int tmp = from;
from = to;
to = tmp;
}
return to + (from - to) * (WELLRNG512a() / (long double)m);
}

The simplest way to get a uniformly distributed random integer between two values is with floating point math.
double get_uniform_rand() {
/*Assumes unsigned 32 bit return value from myrnd in range 0 - 0xFFFFFFFF*/
return (double)myrnd() / (double)0xFFFFFFFF;
}
int32_t get_rnd_in_range(int32_t l, int32_t h) {
return (int32_t)((double)l + get_uniform_rand() * (double)(h-l));
}
This is more of a C approach, as, like user515430 mentioned, there's a standard C++ way of doing this (though I personally have not used it).

Related

Convert int bits to float verbatim and print them

I'm trying to just copy the contents of a 32-bit unsigned int to be used as float. Not casting it, just re-interpreting the integer bits to be used as float. I'm aware memcpy is the most-suggested option for this. However, when I do memcpy from uint_32 to float, and print out the individual bits, I see they are quite different.
Here is my code snippet:
#include <iostream>
#include <stdint.h>
#include <cstring>
using namespace std;
void print_bits(unsigned n) {
unsigned i;
for(i=1u<<31;i > 0; i/=2)
(n & i) ? printf("1"): printf("0");
}
union {
uint32_t u_int;
float u_float;
} my_union;
int main()
{
uint32_t my_int = 0xc6f05705;
float my_float;
//Method 1 using memcpy
memcpy(&my_float, &my_int, sizeof(my_float));
//Print using function
print_bits(my_int);
printf("\n");
print_bits(my_float);
//Print using printf
printf("\n%0x\n",my_int);
printf("%0x\n",my_float);
//Method 2 using unions
my_union.u_int = 0xc6f05705;
printf("union int = %0x\n",my_union.u_int);
printf("union float = %0x\n",my_union.u_float);
return 0;
}
Outputs:
11000110111100000101011100000101
11111111111111111000011111010101
c6f05705
400865
union int = c6f05705
union float = 40087b
Can someone explain what's happening? I expected the bits to match. Didn't work with a union either.
You need to change the function print_bits to
inline
int is_big_endian(void)
{
const union
{
uint32_t i;
char c[sizeof(uint32_t)];
} e = { 0x01000000 };
return e.c[0];
}
void print_bits( const void *src, unsigned int size )
{
//Check for the order of bytes in memory of the compiler:
int t, c;
if (is_big_endian())
{
t = 0;
c = 1;
}
else
{
t = size - 1;
c = -1;
}
for (; t >= 0 && t <= size - 1; t += c)
{ //print the bits of each byte from the MSB to the LSB
unsigned char i;
unsigned char n = ((unsigned char*)src)[t];
for(i = 1 << (CHAR_BIT - 1); i > 0; i /= 2)
{
printf("%d", (n & i) != 0);
}
}
printf("\n");
}
and call it like this:
int a = 7;
print_bits(&a, sizeof(a));
that way there won't be any type conversion when you call print_bits and it would work for any struct size.
EDIT: I replaced 7 with CHAR_BIT - 1 because the size of byte can be different than 8 bits.
EDIT 2: I added support for both little endian and big endian compilers.
Also as #M.M suggested in the comments if you want to you can use template to make the function call be: print_bits(a) instead of print_bits(&a, sizeof(a))

Decoding integer value

I have this program that encodes integer values:
#include "stdafx.h"
#define _SECURE_SCL_DEPRECATE 0
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
vector<unsigned char> nToB(T );
unsigned long ByteToint(vector<unsigned char> v)
{
unsigned long int a = 0;
int s = v.size();
for (int i = 0; i<s ; i++)
{
a |= (v[s - 1 - i] << (8 * (s - i - 1)));
}
return a;
}
static unsigned long int Encode7Bits(unsigned long int);
int main()
{
cout << Encode7Bits(420);
getchar();
return 0;
}
static unsigned long int Encode7Bits( unsigned long int x)
{
vector<unsigned char> Result;
do
{
unsigned long int tmp = x & 0x7f;
x = x >> 7;
if (x > 0)
tmp |= 0x80;
Result.push_back((unsigned char )tmp);
} while (x > 0);
return ByteToint(Result);
}
If the argument to this function is 420 it will return 932.
My question is whether it is possible to do the reverse operation, a decoding function that given 932, returns 420.
No it isn't.
|= is non-invertible in the sense that if you write c = a | b, then given c, and either a or b, you can't recover the other variable.
The bitwise operators << and >> are obviously lossy since they introduce 0 bits.
You'll have better luck with XOR: if you write c = a ^ b, then c ^ b will be a.

How can I improve this Pollard's rho algorithm to handle products of semi-large primes?

Below is my implementation of Pollard's rho algorithm for prime factorization:
#include <vector>
#include <queue>
#include <gmpxx.h>
// Interface to the GMP random number functions.
gmp_randclass rng(gmp_randinit_default);
// Returns a divisor of N using Pollard's rho method.
mpz_class getDivisor(const mpz_class &N)
{
mpz_class c = rng.get_z_range(N);
mpz_class x = rng.get_z_range(N);
mpz_class y = x;
mpz_class d = 1;
mpz_class z;
while (d == 1) {
x = (x*x + c) % N;
y = (y*y + c) % N;
y = (y*y + c) % N;
z = x - y;
mpz_gcd(d.get_mpz_t(), z.get_mpz_t(), N.get_mpz_t());
}
return d;
}
// Adds the prime factors of N to the given vector.
void factor(const mpz_class &N, std::vector<mpz_class> &factors)
{
std::queue<mpz_class> to_factor;
to_factor.push(N);
while (!to_factor.empty()) {
mpz_class n = to_factor.front();
to_factor.pop();
if (n == 1) {
continue; // Trivial factor.
} else if (mpz_probab_prime_p(n.get_mpz_t(), 5)) {
// n is a prime.
factors.push_back(n);
} else {
// n is a composite, so push its factors on the queue.
mpz_class d = getDivisor(n);
to_factor.push(d);
to_factor.push(n/d);
}
}
}
It's essentially a straight translation of the pseudocode on Wikipedia, and relies on GMP for big numbers and for primality testing. The implementation works well and can factor primes such as
1000036317378699858851366323 = 1000014599 * 1000003357 * 1000018361
but will choke on e.g.
1000000000002322140000000048599822299 = 1000000000002301019 * 1000000000000021121
My question is: Is there anything I can do to improve on this, short of switching to a more complex factorization algorithm such as Quadratic sieve?
I know one improvement could be to first do some trial divisions by pre-computed primes, but that would not help for products of a few large primes such as the above.
I'm interested in any tips on improvements to the basic Pollard's rho method to get it to handle larger composites of only a few prime factors. Of course if you find any stupidities in the code above, I'm interested in those as well.
For full disclosure: This is a homework assignment, so general tips and pointers are better than fully coded solutions. With this very simple approach I already get a passing grade on the assignment, but would of course like to improve.
Thanks in advance.
You are using the original version of the rho algorithm due to Pollard. Brent's variant makes two improvements: Floyd's tortoise-and-hare cycle-finding algorithm is replaced by a cycle-finding algorithm developed by Brent, and the gcd calculation is delayed so it is performed only once every hundred or so times through the loop instead of every time. But those changes only get a small improvement, maybe 25% or so, and won't allow you to factor the large numbers you are talking about. Thus, you will need a better algorithm: SQUFOF might work for semi-primes the size that you mention, or you could implement quadratic sieve or the elliptic curve method. I have discussion and implementation of all those algorithms at my blog.
Part 1
Very interesting question you have, thanks!
Decided to implement my own very complex C++ solution of your task from scratch. Although you asked not to write code, still I did it fully only to have proof of concept, to check real speed and timings.
To tell in advance, I improved speed of you program 250-500x times (see Part 2).
Besides well known algorithm described in Wikipedia I did following extra optimizations:
Made most of computations in compile time. This is main feature of my code. Input number N is provided at compile time as long macro constant. This ensures that compiler does half of optimizations at compile time like inlining constants and doing optimizing division and other arithmetics. As a drawback, you have to re-compile program every time when you change a number that you want to factor.
Additionally to 1. I also did support of runtime-only value of N. This is needed to do real comparison of speed in different environments.
One more very important speed improvement is that I used Montgomery Reduction to speedup modulus division. This Montgomery speeds up all computations 2-2.5x times. Besides Montgomery you can also use Barrett Reduction. Both Montgomery and Barrett replace single expensive division with several multiplications and additions, which makes division very fast.
Unlike in your code I do GCD (Greatest Common Divisor) computation very rarely, once in 8 000 - 16 000 iterations. Because GCD is very expensive, it needs around 128 expensive divisions for 128-bit numbers. Instead of computing GCD(x - y, N) every time you can notice that it is enough to accumulate product prod = (prod * (x - y)) % N and later after thousand of such iterations just compute GCD(prod, N). This is easily derived from fact that GCD((a * b * c) % N, N) = GCD(GCD(a, N) * GCD(b, N) * GCD(c, N), N).
One very advanced and fast optimization that I did is implemented my own uint128 and uint256 with all necessary sub-optimizations needed for my task. This optimization is only posted in code by me in Part 2 of my answer, see this part after first code.
As a result of above steps, total speed of Pollard Rho is increased 50-100x times, especially due to doing GCD only once in thousand steps. This speed is enough even to compute your biggest number provided in your question.
Besides algorithms described above I also used following extra algorithms: Extended Euclidean Algorithm (for computing coefficients for modular inverse), Modular Multiplicative Inverse, Euclidean Algorithm (for computing GCD), Modular Binary Exponentiation, Trial Division (for checking primality of small numbers), Fermat Primality Test, as already mentioned Montgomery Reduction and Pollard Rho itself.
I did following timings and speed measurements:
N 1000036317378699858851366323 (90 bits)
1000003357 (30 bits) * 1000014599 (30 bits) * 1000018361 (30 bits)
PollardRho time 0.1 secs, tries 1 iterations 25599 (2^14.64)
N 780002082420246798979794021150335143 (120 bits)
244300526707007 (48 bits) * 3192797383346267127449 (72 bits)
PollardRho time 32 secs, tries 1 iterations 25853951 (2^24.62)
NO-Montgomery time 70 secs
N 614793320656537415355785711660734447 (120 bits)
44780536225818373 (56 bits) * 13729029897191722339 (64 bits)
PollardRho time 310 secs, tries 1 iterations 230129663 (2^27.78)
N 1000000000002322140000000048599822299 (120 bits)
1000000000000021121 (60 bits) * 1000000000002301019 (60 bits)
PollardRho time 2260 secs, tries 1 iterations 1914068991 (2^30.83)
As you can see above your smaller number takes just 0.1 second to factor, while your bigger number (that you failed to factor at all) takes quite affordable time, 2260 seconds (a bit more than half hour). Also you can see that I created myself a number with 48-bit smallest factor, and another number with 56-bit smaller factor.
In general a rule is such that if you have smallest factor of K-bit then it takes 2^(K/2) iterations of Pollard Rho to compute this factor. Unlike for example Trial division algorithm which needs square times bigger time of 2^K for K-bit factor.
In my code see very start of file, there is a bunch of lines #define NUM, each defining compile time constant containing a number. You can comment out any line or change value of a number or add a new line with new number. Then re-compile program and run it to see results.
Before below code don't forget to click on Try it online! link to check code run on GodBolt server. Also see example Console Output after code.
Try it online!
#include <cstdint>
#include <tuple>
#include <iostream>
#include <iomanip>
#include <chrono>
#include <random>
#include <stdexcept>
#include <string>
#include <mutex>
#include <cmath>
#include <type_traits>
#include <boost/multiprecision/cpp_int.hpp>
//#define NUM "1000036317378699858851366323" // 90 bits, 1000003357 (30 bits) * 1000014599 (30 bits) * 1000018361 (30 bits), PollardRho time 0.1 secs, tries 1 iterations 25599 (2^14.64)
#define NUM "780002082420246798979794021150335143" // 120 bits, 244300526707007 (48 bits) * 3192797383346267127449 (72 bits), PollardRho time 32 secs, tries 1 iterations 25853951 (2^24.62), NO-Montgomery time 70 secs
//#define NUM "614793320656537415355785711660734447" // 120 bits, 44780536225818373 (56 bits) * 13729029897191722339 (64 bits), PollardRho time 310 secs, tries 1 iterations 230129663 (2^27.78)
//#define NUM "1000000000002322140000000048599822299" // 120 bits, 1000000000000021121 (60 bits) * 1000000000002301019 (60 bits), PollardRho time 2260 secs, tries 1 iterations 1914068991 (2^30.83)
#define IS_DEBUG 0
#define IS_COMPILE_TIME 1
bool constexpr use_montg = 1;
size_t constexpr gcd_per_nloops = 1 << 14;
#if defined(_MSC_VER) && !defined(__clang__)
#define HAS_INT128 0
#else
#define HAS_INT128 1
#endif
#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line " + std::to_string(__LINE__) + "! Msg: '" + std::string(msg) + "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")
#define COUT(code) { std::unique_lock<std::mutex> lock(cout_mux); std::cout code; std::cout << std::flush; }
#if IS_DEBUG
#define LN { COUT(<< "LN " << __LINE__ << std::endl); }
#define DUMP(var) { COUT(<< __LINE__ << " : " << #var << " = (" << (var) << ")" << std::endl); }
#else
#define LN
#define DUMP(var)
#endif
#define bisizeof(x) (sizeof(x) * 8)
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using u128 = boost::multiprecision::uint128_t;
using i128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u192 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<192, 192, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using i192 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<192, 192, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u256 = boost::multiprecision::uint256_t;
using i256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u384 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<384, 384, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using i384 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<384, 384, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
#if HAS_INT128
using u128_cl = unsigned __int128;
using i128_cl = signed __int128;
#endif
template <typename T> struct DWordOf;
template <> struct DWordOf<u64> : std::type_identity<u128> {};
template <> struct DWordOf<i64> : std::type_identity<i128> {};
template <> struct DWordOf<u128> : std::type_identity<u256> {};
template <> struct DWordOf<i128> : std::type_identity<i256> {};
#if HAS_INT128
template <> struct DWordOf<u128_cl> : std::type_identity<u256> {};
template <> struct DWordOf<i128_cl> : std::type_identity<i256> {};
#endif
template <typename T>
using DWordOfT = typename DWordOf<T>::type;
template <typename T> struct SignedOf;
template <> struct SignedOf<u64> : std::type_identity<i64> {};
template <> struct SignedOf<i64> : std::type_identity<i64> {};
template <> struct SignedOf<u128> : std::type_identity<i128> {};
template <> struct SignedOf<i128> : std::type_identity<i128> {};
#if HAS_INT128
template <> struct SignedOf<u128_cl> : std::type_identity<i128> {};
template <> struct SignedOf<i128_cl> : std::type_identity<i128> {};
#endif
template <typename T>
using SignedOfT = typename SignedOf<T>::type;
template <typename T> struct BiSizeOf;
template <> struct BiSizeOf<u64> : std::integral_constant<size_t, 64> {};
template <> struct BiSizeOf<u128> : std::integral_constant<size_t, 128> {};
template <> struct BiSizeOf<u192> : std::integral_constant<size_t, 192> {};
template <> struct BiSizeOf<u256> : std::integral_constant<size_t, 256> {};
template <> struct BiSizeOf<u384> : std::integral_constant<size_t, 384> {};
#if HAS_INT128
template <> struct BiSizeOf<u128_cl> : std::integral_constant<size_t, 128> {};
#endif
template <typename T>
size_t constexpr BiSizeOfT = BiSizeOf<T>::value;
static std::mutex cout_mux;
double Time() {
static auto const gtb = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::duration<double>>(
std::chrono::high_resolution_clock::now() - gtb).count();
}
template <typename T, typename DT = DWordOfT<T>>
constexpr DT MulD(T const & a, T const & b) {
return DT(a) * b;
}
template <typename T>
constexpr auto EGCD(T const & a, T const & b) {
using ST = SignedOfT<T>;
using DST = DWordOfT<ST>;
T ro = 0, r = 0, qu = 0, re = 0;
ST so = 0, s = 0;
std::tie(ro, r, so, s) = std::make_tuple(a, b, 1, 0);
while (r != 0) {
std::tie(qu, re) = std::make_tuple(ro / r, ro % r);
std::tie(ro, r) = std::make_tuple(r, re);
std::tie(so, s) = std::make_tuple(s, ST(so - DST(s) * ST(qu)));
}
ST const to = ST((DST(ro) - DST(a) * so) / ST(b));
return std::make_tuple(ro, so, to);
}
template <typename T>
constexpr T ModInv(T x, T mod) {
using ST = SignedOfT<T>;
using DT = DWordOfT<T>;
x %= mod;
auto [g, s, t] = EGCD(x, mod);
//ASSERT(g == 1);
if (s < 0) {
//ASSERT(ST(mod) + s >= 0);
s += mod;
} else {
//ASSERT(s < mod);
}
//ASSERT((DT(x) * s) % mod == 1);
return T(s);
}
template <typename ST>
constexpr std::tuple<ST, ST, ST, ST> MontgKRR(ST n) {
size_t constexpr ST_bisize = BiSizeOfT<ST>;
using DT = DWordOfT<ST>;
DT constexpr r = DT(1) << ST_bisize;
ST const rmod = ST(r % n), rmod2 = ST(MulD<ST>(rmod, rmod) % n), rinv = ModInv<ST>(rmod, n);
DT const k0 = (r * DT(rinv) - 1) / n;
//ASSERT(k0 < (DT(1) << ST_bisize));
ST const k = ST(k0);
return std::make_tuple(k, rmod, rmod2, rinv);
}
template <typename T>
constexpr T GCD(T a, T b) {
while (b != 0)
std::tie(a, b) = std::make_tuple(b, a % b);
return a;
}
template <typename T>
T PowMod(T a, T b, T const & c) {
// https://en.wikipedia.org/wiki/Modular_exponentiation
using DT = DWordOfT<T>;
T r = 1;
while (b != 0) {
if (u32(b) & 1)
r = T(MulD<T>(r, a) % c);
a = T(MulD<T>(a, a) % c);
b >>= 1;
}
return r;
}
template <typename T>
std::pair<bool, bool> IsProbablyPrime_TrialDiv(T const n, u64 limit = u64(-1)) {
// https://en.wikipedia.org/wiki/Trial_division
if (n <= 16)
return {n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13, true};
if ((n & 1) == 0)
return {false, true};
u64 d = 0;
for (d = 3; d < limit && d * d <= n; d += 2)
if (n % d == 0)
return {false, true};
return {true, d * d > n};
}
template <typename T>
bool IsProbablyPrime_Fermat(T const n, size_t ntrials = 32) {
// https://en.wikipedia.org/wiki/Fermat_primality_test
if (n <= 16)
return n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13;
thread_local std::mt19937_64 rng{123};
u64 const rand_end = n - 3 <= u64(-5) ? u64(n - 3) : u64(-5);
for (size_t trial = 0; trial < ntrials; ++trial)
if (PowMod<T>(rng() % rand_end + 2, n - 1, n) != 1)
return false;
return true;
}
template <typename T>
bool IsProbablyPrime(T const n) {
if (n < (1 << 12))
return IsProbablyPrime_TrialDiv(n).first;
return IsProbablyPrime_Fermat(n);
}
template <typename T>
std::string IntToStr(T n) {
if (n == 0)
return "0";
std::string r;
while (n != 0) {
u32 constexpr mod = 1'000'000'000U;
std::ostringstream ss;
auto const nm = u32(n % mod);
n /= mod;
if (n != 0)
ss << std::setw(9) << std::setfill('0');
ss << nm;
r = ss.str() + r;
}
return r;
}
template <typename T>
constexpr T ParseNum(char const * s) {
size_t len = 0;
for (len = 0; s[len]; ++len);
T r = 0;
for (size_t i = 0; i < len; ++i) {
r *= 10;
r += s[i] - '0';
}
return r;
}
template <typename T>
std::tuple<T, std::vector<T>, std::vector<T>> Factor_PollardRho(
#if !IS_COMPILE_TIME
T const & n,
#endif
u64 limit = u64(-1), size_t ntrials = 6) {
size_t constexpr T_bisize = BiSizeOfT<T>;
// https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
using DT = DWordOfT<T>;
#if IS_COMPILE_TIME
static auto constexpr n = ParseNum<T>(NUM);
#endif
if (n <= 1)
return {n, {}, {}};
if (IsProbablyPrime<T>(n))
return {n, {n}, {}};
#if IS_COMPILE_TIME
static auto constexpr montg_krr = MontgKRR(n);
static T constexpr mk = std::get<0>(montg_krr), mrm = std::get<1>(montg_krr), mrm2 = std::get<2>(montg_krr), mri = std::get<3>(montg_krr),
mone = use_montg ? mrm : 1, mone2 = use_montg ? mrm2 : 1;
#else
static auto const montg_krr = MontgKRR(n);
static T const mk = std::get<0>(montg_krr), mrm = std::get<1>(montg_krr), mrm2 = std::get<2>(montg_krr), mri = std::get<3>(montg_krr),
mone = use_montg ? mrm : 1, mone2 = use_montg ? mrm2 : 1;
#endif
auto AdjustL = [&](T x) -> T {
if constexpr(1) {
while (x >= n)
x -= n;
return x;
} else {
using SiT = SignedOfT<T>;
return x - (n & (~T(SiT(x - n) >> (T_bisize - 1))));
}
};
auto MontgModL = [&](DT const & x) -> T {
if constexpr(!use_montg)
return T(x % n);
else
return T((x + MulD<T>(n, T(x) * mk)) >> T_bisize);
};
auto ToMontgL = [&](T const & x) -> T {
if constexpr(!use_montg)
return x;
else
return MontgModL(MulD<T>(x, mrm2));
};
auto FromMontgL = [&](T const & x) -> T {
if constexpr(!use_montg)
return x;
else
return AdjustL(MontgModL(x));
};
auto DumpMontgX = [&](char const * name, T const & x, bool from = true){
if constexpr(1) {
COUT(<< __LINE__ << " : " << name << " = " << IntToStr(from ? FromMontgL(x) : x) << std::endl);
}
};
auto f = [&](T x){ return MontgModL(MulD<T>(x, x) + mone2); };
#if IS_DEBUG
#define DUMPM(x) DumpMontgX(#x, x)
#define DUMPI(x) DumpMontgX(#x, x, false)
#else
#define DUMPM(x)
#define DUMPI(x)
#endif
ASSERT(3 <= n);
size_t cnt = 0;
u64 const distr_end = n - 2 <= u64(-5) ? u64(n - 2) : u64(-5);
thread_local std::mt19937_64 rng{123};
for (size_t itry = 0; itry < ntrials; ++itry) {
bool failed = false;
u64 const rnd = rng() % distr_end + 1;
T x = ToMontgL(rnd);
u64 sum_cycles = 0;
for (u64 cycle = 1;; cycle <<= 1) {
T y = x, m = mone, xstart = x, ny = 0;
while (ny < y)
ny += n;
ny -= y;
auto ILast = [&](auto istart){
size_t ri = istart + gcd_per_nloops - 1;
if (ri < cycle)
return ri;
else
return cycle - 1;
};
for (u64 i = 0, istart = 0, ilast = ILast(istart); i < cycle; ++i) {
x = f(x);
m = MontgModL(MulD<T>(m, ny + x));
if (i < ilast)
continue;
cnt += ilast + 1 - istart;
if (cnt >= limit)
return {n, {}, {n}};
if (GCD<T>(n, FromMontgL(m)) == 1) {
istart = i + 1;
ilast = ILast(istart);
xstart = x;
continue;
}
T x2 = xstart;
for (u64 i2 = istart; i2 <= i; ++i2) {
x2 = f(x2);
auto const g = GCD<T>(n, FromMontgL(ny + x2));
if (g == 1) {
continue;
}
sum_cycles += i + 1;
if (g == n) {
failed = true;
break;
}
#if 0
auto res0 = Factor_PollardRho<T>(g, limit, ntrials);
auto res1 = Factor_PollardRho<T>(n / g, limit, ntrials);
res0.first.insert(res0.first.end(), res1.first.begin(), res1.first.end());
res0.second.insert(res0.second.end(), res1.second.begin(), res1.second.end());
#endif
ASSERT(n % g == 0);
COUT(<< "PollardRho tries " << (itry + 1) << " iterations " << sum_cycles << " (2^" << std::fixed << std::setprecision(2) << std::log2(std::max<size_t>(1, sum_cycles)) << ")" << std::endl);
if (IsProbablyPrime<T>(n / g))
return {n, {g, n / g}, {}};
else
return {n, {g}, {n / g}};
}
if (failed)
break;
ASSERT(false);
}
sum_cycles += cycle;
if (failed)
break;
}
}
return {n, {}, {n}};
}
template <typename T>
void ShowFactors(std::tuple<T, std::vector<T>, std::vector<T>> fs) {
auto [N, a, b] = fs;
std::cout << "Factors of " << IntToStr(N) << " (2^" << std::fixed << std::setprecision(3) << std::log2(double(std::max<T>(1, N))) << "):" << std::endl;
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
for (auto const & x: a)
std::cout << x << " ";
std::cout << std::endl;
if (!b.empty()) {
std::cout << "Unfactored:" << std::endl;
for (auto const & x: b)
std::cout << x << " ";
std::cout << std::endl;
}
}
int main() {
try {
using T = u128;
#if !IS_COMPILE_TIME
std::string s;
COUT(<< "Enter number: ");
std::cin >> s;
auto const N = ParseNum<T>(s.c_str());
#endif
auto const tim = Time();
ShowFactors(Factor_PollardRho<T>(
#if !IS_COMPILE_TIME
N
#endif
));
COUT(<< "Time " << std::fixed << std::setprecision(3) << (Time() - tim) << " sec" << std::endl);
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Console Output:
PollardRho tries 1 iterations 25853951 (2^24.62)
Factors of 780002082420246798979794021150335143 (2^119.231):
244300526707007 3192797383346267127449
Time 35.888 sec
Part 2
Decided to do even further improvements, by implementing my own highly optimal uint128 and uint256, meaning long arithmetics, same like done in Boost or GMP.
Not to dwell into all the details, I optimized every line and every method of these classes. Especially all those methods that deal with operations needed for factorization.
This improved version gives 6x times more speed, compared to Part 1 of my answer, meaning if first version takes 30 seconds to finish, this second version takes 5 seconds.
As you can see in Console Output at the very end of my post, your biggest number takes just 420 seconds to factor. This is 5.4x times faster compared to 2260 seconds of the first part of this answer.
CODE GOES HERE. Only because of StackOverflow limit of 30 000 symbols per post, I can't inline 2nd code here, because it alone is 26 KB in size. Hence I'm providing this code as Gist link below and also through Try it online! link (to run online on GodBolt server):
Github Gist source code
Try it online!
Console Output:
PollardRho tries 1 iterations 32767 (2^15.00)
Factors of 1000036317378699858851366323 (2^89.692):
1000014599
Unfactored:
1000021718061637877
Time 0.086 sec
PollardRho tries 1 iterations 25853951 (2^24.62)
Factors of 780002082420246798979794021150335143 (2^119.231):
244300526707007 3192797383346267127449
Time 5.830 sec
PollardRho tries 1 iterations 230129663 (2^27.78)
Factors of 614793320656537415355785711660734447 (2^118.888):
44780536225818373 13729029897191722339
Time 49.446 sec
PollardRho tries 1 iterations 1914077183 (2^30.83)
Factors of 1000000000002322140000000048599822299 (2^119.589):
1000000000000021121 1000000000002301019
Time 419.680 sec

Any way faster than pow() to compute an integer power of 10 in C++?

I know power of 2 can be implemented using << operator.
What about power of 10? Like 10^5? Is there any way faster than pow(10,5) in C++? It is a pretty straight-forward computation by hand. But seems not easy for computers due to binary representation of the numbers... Let us assume I am only interested in integer powers, 10^n, where n is an integer.
Something like this:
int quick_pow10(int n)
{
static int pow10[10] = {
1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000, 1000000000
};
return pow10[n];
}
Obviously, can do the same thing for long long.
This should be several times faster than any competing method. However, it is quite limited if you have lots of bases (although the number of values goes down quite dramatically with larger bases), so if there isn't a huge number of combinations, it's still doable.
As a comparison:
#include <iostream>
#include <cstdlib>
#include <cmath>
static int quick_pow10(int n)
{
static int pow10[10] = {
1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000, 1000000000
};
return pow10[n];
}
static int integer_pow(int x, int n)
{
int r = 1;
while (n--)
r *= x;
return r;
}
static int opt_int_pow(int n)
{
int r = 1;
const int x = 10;
while (n)
{
if (n & 1)
{
r *= x;
n--;
}
else
{
r *= x * x;
n -= 2;
}
}
return r;
}
int main(int argc, char **argv)
{
long long sum = 0;
int n = strtol(argv[1], 0, 0);
const long outer_loops = 1000000000;
if (argv[2][0] == 'a')
{
for(long i = 0; i < outer_loops / n; i++)
{
for(int j = 1; j < n+1; j++)
{
sum += quick_pow10(n);
}
}
}
if (argv[2][0] == 'b')
{
for(long i = 0; i < outer_loops / n; i++)
{
for(int j = 1; j < n+1; j++)
{
sum += integer_pow(10,n);
}
}
}
if (argv[2][0] == 'c')
{
for(long i = 0; i < outer_loops / n; i++)
{
for(int j = 1; j < n+1; j++)
{
sum += opt_int_pow(n);
}
}
}
std::cout << "sum=" << sum << std::endl;
return 0;
}
Compiled with g++ 4.6.3, using -Wall -O2 -std=c++0x, gives the following results:
$ g++ -Wall -O2 -std=c++0x pow.cpp
$ time ./a.out 8 a
sum=100000000000000000
real 0m0.124s
user 0m0.119s
sys 0m0.004s
$ time ./a.out 8 b
sum=100000000000000000
real 0m7.502s
user 0m7.482s
sys 0m0.003s
$ time ./a.out 8 c
sum=100000000000000000
real 0m6.098s
user 0m6.077s
sys 0m0.002s
(I did have an option for using pow as well, but it took 1m22.56s when I first tried it, so I removed it when I decided to have optimised loop variant)
There are certainly ways to compute integral powers of 10 faster than using std::pow()! The first realization is that pow(x, n) can be implemented in O(log n) time. The next realization is that pow(x, 10) is the same as (x << 3) * (x << 1). Of course, the compiler knows the latter, i.e., when you are multiplying an integer by the integer constant 10, the compiler will do whatever is fastest to multiply by 10. Based on these two rules it is easy to create fast computations, even if x is a big integer type.
In case you are interested in games like this:
A generic O(log n) version of power is discussed in Elements of Programming.
Lots of interesting "tricks" with integers are discussed in Hacker's Delight.
A solution for any base using template meta-programming :
template<int E, int N>
struct pow {
enum { value = E * pow<E, N - 1>::value };
};
template <int E>
struct pow<E, 0> {
enum { value = 1 };
};
Then it can be used to generate a lookup-table that can be used at runtime :
template<int E>
long long quick_pow(unsigned int n) {
static long long lookupTable[] = {
pow<E, 0>::value, pow<E, 1>::value, pow<E, 2>::value,
pow<E, 3>::value, pow<E, 4>::value, pow<E, 5>::value,
pow<E, 6>::value, pow<E, 7>::value, pow<E, 8>::value,
pow<E, 9>::value
};
return lookupTable[n];
}
This must be used with correct compiler flags in order to detect the possible overflows.
Usage example :
for(unsigned int n = 0; n < 10; ++n) {
std::cout << quick_pow<10>(n) << std::endl;
}
An integer power function (which doesn't involve floating-point conversions and computations) may very well be faster than pow():
int integer_pow(int x, int n)
{
int r = 1;
while (n--)
r *= x;
return r;
}
Edit: benchmarked - the naive integer exponentiation method seems to outperform the floating-point one by about a factor of two:
h2co3-macbook:~ h2co3$ cat quirk.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <math.h>
int integer_pow(int x, int n)
{
int r = 1;
while (n--)
r *= x;
return r;
}
int main(int argc, char *argv[])
{
int x = 0;
for (int i = 0; i < 100000000; i++) {
x += powerfunc(i, 5);
}
printf("x = %d\n", x);
return 0;
}
h2co3-macbook:~ h2co3$ clang -Wall -o quirk quirk.c -Dpowerfunc=integer_pow
h2co3-macbook:~ h2co3$ time ./quirk
x = -1945812992
real 0m1.169s
user 0m1.164s
sys 0m0.003s
h2co3-macbook:~ h2co3$ clang -Wall -o quirk quirk.c -Dpowerfunc=pow
h2co3-macbook:~ h2co3$ time ./quirk
x = -2147483648
real 0m2.898s
user 0m2.891s
sys 0m0.004s
h2co3-macbook:~ h2co3$
No multiplication and no table version:
//Nx10^n
int Npow10(int N, int n){
N <<= n;
while(n--) N += N << 2;
return N;
}
Here is a stab at it:
// specialize if you have a bignum integer like type you want to work with:
template<typename T> struct is_integer_like:std::is_integral<T> {};
template<typename T> struct make_unsigned_like:std::make_unsigned<T> {};
template<typename T, typename U>
T powT( T base, U exponent ) {
static_assert( is_integer_like<U>::value, "exponent must be integer-like" );
static_assert( std::is_same< U, typename make_unsigned_like<U>::type >::value, "exponent must be unsigned" );
T retval = 1;
T& multiplicand = base;
if (exponent) {
while (true) {
// branch prediction will be awful here, you may have to micro-optimize:
retval *= (exponent&1)?multiplicand:1;
// or /2, whatever -- `>>1` is probably faster, esp for bignums:
exponent = exponent>>1;
if (!exponent)
break;
multiplicand *= multiplicand;
}
}
return retval;
}
What is going on above is a few things.
First, so BigNum support is cheap, it is templateized. Out of the box, it supports any base type that supports *= own_type and either can be implicitly converted to int, or int can be implicitly converted to it (if both is true, problems will occur), and you need to specialize some templates to indicate that the exponent type involved is both unsigned and integer-like.
In this case, integer-like and unsigned means that it supports &1 returning bool and >>1 returning something it can be constructed from and eventually (after repeated >>1s) reaches a point where evaluating it in a bool context returns false. I used traits classes to express the restriction, because naive use by a value like -1 would compile and (on some platforms) loop forever, while (on others) would not.
Execution time for this algorithm, assuming multiplication is O(1), is O(lg(exponent)), where lg(exponent) is the number of times it takes to <<1 the exponent before it evaluates as false in a boolean context. For traditional integer types, this would be the binary log of the exponents value: so no more than 32.
I also eliminated all branches within the loop (or, made it obvious to existing compilers that no branch is needed, more precisely), with just the control branch (which is true uniformly until it is false once). Possibly eliminating even that branch might be worth it for high bases and low exponents...
Now, with constexpr, you can do like so:
constexpr int pow10(int n) {
int result = 1;
for (int i = 1; i<=n; ++i)
result *= 10;
return result;
}
int main () {
int i = pow10(5);
}
i will be calculated at compile time. ASM generated for x86-64 gcc 9.2:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 100000
mov eax, 0
pop rbp
ret
You can use the lookup table which will be by far the fastest
You can also consider using this:-
template <typename T>
T expt(T p, unsigned q)
{
T r(1);
while (q != 0) {
if (q % 2 == 1) { // q is odd
r *= p;
q--;
}
p *= p;
q /= 2;
}
return r;
}
This function will calculate x ^ y much faster then pow. In case of integer values.
int pot(int x, int y){
int solution = 1;
while(y){
if(y&1)
solution*= x;
x *= x;
y >>= 1;
}
return solution;
}
A generic table builder based on constexpr functions. The floating point part requires c++20 and gcc, but the non-floating point part works for c++17. If you change the "auto" type param to "long" you can use c++14. Not properly tested.
#include <cstdio>
#include <cassert>
#include <cmath>
// Precomputes x^N
// Inspired by https://stackoverflow.com/a/34465458
template<auto x, unsigned char N, typename AccumulatorType>
struct PowTable {
constexpr PowTable() : mTable() {
AccumulatorType p{ 1 };
for (unsigned char i = 0; i < N; ++i) {
p *= x;
mTable[i] = p;
}
}
AccumulatorType operator[](unsigned char n) const {
assert(n < N);
return mTable[n];
}
AccumulatorType mTable[N];
};
long pow10(unsigned char n) {
static constexpr PowTable<10l, 10, long> powTable;
return powTable[n-1];
}
double powe(unsigned char n) {
static constexpr PowTable<2.71828182845904523536, 10, double> powTable;
return powTable[n-1];
}
int main() {
printf("10^3=%ld\n", pow10(3));
printf("e^2=%f", powe(2));
assert(pow10(3) == 1000);
assert(powe(2) - 7.389056 < 0.001);
}
Based on Mats Petersson approach, but compile time generation of cache.
#include <iostream>
#include <limits>
#include <array>
// digits
template <typename T>
constexpr T digits(T number) {
return number == 0 ? 0
: 1 + digits<T>(number / 10);
}
// pow
// https://stackoverflow.com/questions/24656212/why-does-gcc-complain-error-type-intt-of-template-argument-0-depends-on-a
// unfortunatly we can't write `template <typename T, T N>` because of partial specialization `PowerOfTen<T, 1>`
template <typename T, uintmax_t N>
struct PowerOfTen {
enum { value = 10 * PowerOfTen<T, N - 1>::value };
};
template <typename T>
struct PowerOfTen<T, 1> {
enum { value = 1 };
};
// sequence
template<typename T, T...>
struct pow10_sequence { };
template<typename T, T From, T N, T... Is>
struct make_pow10_sequence_from
: make_pow10_sequence_from<T, From, N - 1, N - 1, Is...> {
//
};
template<typename T, T From, T... Is>
struct make_pow10_sequence_from<T, From, From, Is...>
: pow10_sequence<T, Is...> {
//
};
// base10list
template <typename T, T N, T... Is>
constexpr std::array<T, N> base10list(pow10_sequence<T, Is...>) {
return {{ PowerOfTen<T, Is>::value... }};
}
template <typename T, T N>
constexpr std::array<T, N> base10list() {
return base10list<T, N>(make_pow10_sequence_from<T, 1, N+1>());
}
template <typename T>
constexpr std::array<T, digits(std::numeric_limits<T>::max())> base10list() {
return base10list<T, digits(std::numeric_limits<T>::max())>();
};
// main pow function
template <typename T>
static T template_quick_pow10(T n) {
static auto values = base10list<T>();
return values[n];
}
// client code
int main(int argc, char **argv) {
long long sum = 0;
int n = strtol(argv[1], 0, 0);
const long outer_loops = 1000000000;
if (argv[2][0] == 't') {
for(long i = 0; i < outer_loops / n; i++) {
for(int j = 1; j < n+1; j++) {
sum += template_quick_pow10(n);
}
}
}
std::cout << "sum=" << sum << std::endl;
return 0;
}
Code does not contain quick_pow10, integer_pow, opt_int_pow for better readability, but tests done with them in the code.
Compiled with gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5), using -Wall -O2 -std=c++0x, gives the following results:
$ g++ -Wall -O2 -std=c++0x main.cpp
$ time ./a.out 8 a
sum=100000000000000000
real 0m0.438s
user 0m0.432s
sys 0m0.008s
$ time ./a.out 8 b
sum=100000000000000000
real 0m8.783s
user 0m8.777s
sys 0m0.004s
$ time ./a.out 8 c
sum=100000000000000000
real 0m6.708s
user 0m6.700s
sys 0m0.004s
$ time ./a.out 8 t
sum=100000000000000000
real 0m0.439s
user 0m0.436s
sys 0m0.000s
if you want to calculate, e.g.,10^5, then you can:
int main() {
cout << (int)1e5 << endl; // will print 100000
cout << (int)1e3 << endl; // will print 1000
return 0;
}
result *= 10 can also be written as result = (result << 3) + (result << 1)
constexpr int pow10(int n) {
int result = 1;
for (int i = 0; i < n; i++) {
result = (result << 3) + (result << 1);
}
return result;
}

convert 64-bit binary string representation of a double number back to double number in c++

I have a IEEE754 Double precision 64-bit binary string representation of a double number.
example : double value = 0.999;
Its binary representation is "0011111111101111111101111100111011011001000101101000011100101011"
I want to convert this string back to a double number in c++.
I dont want to use any external libraries or .dll's as my program would operate in any platform.
C string solution:
#include <cstring> // needed for all three solutions because of memcpy
double bitstring_to_double(const char* p)
{
unsigned long long x = 0;
for (; *p; ++p)
{
x = (x << 1) + (*p - '0');
}
double d;
memcpy(&d, &x, 8);
return d;
}
std::string solution:
#include <string>
double bitstring_to_double(const std::string& s)
{
unsigned long long x = 0;
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
{
x = (x << 1) + (*it - '0');
}
double d;
memcpy(&d, &x, 8);
return d;
}
generic solution:
template<typename InputIterator>
double bitstring_to_double(InputIterator begin, InputIterator end)
{
unsigned long long x = 0;
for (; begin != end; ++begin)
{
x = (x << 1) + (*begin - '0');
}
double d;
memcpy(&d, &x, 8);
return d;
}
example calls:
#include <iostream>
int main()
{
const char * p = "0011111111101111111101111100111011011001000101101000011100101011";
std::cout << bitstring_to_double(p) << '\n';
std::string s(p);
std::cout << bitstring_to_double(s) << '\n';
std::cout << bitstring_to_double(s.begin(), s.end()) << '\n';
std::cout << bitstring_to_double(p + 0, p + 64) << '\n';
}
Note: I assume unsigned long long has 64 bits. A cleaner solution would be to include <cstdint> and use uint64_t instead, assuming your compiler is up to date and provides that C++11 header.
A starting point would be to iterate through the individual characters in the string and set individual bits of an existing double.
Is it really a character string of binary bits? If so, first convert to a 64-bit int. Then either use a library routine (probably there is one somewhere), or more simply, use a double aliased over the 64-bit int to convert to double.
(If it's already a 64-bit int then skip the first step.)
Ignoring byte-ordering issues, but I suppose this should be a viable option:
The below has an outcome of .999 on i386 with gcc. See it live: https://ideone.com/i4ygJ
#include <cstdint>
#include <sstream>
#include <iostream>
#include <bitset>
int main()
{
std::istringstream iss("0011111111101111111101111100111011011001000101101000011100101011");
std::bitset<32> hi, lo;
if (iss >> hi >> lo)
{
struct { uint32_t lo, hi; } words = { lo.to_ulong(), hi.to_ulong() };
double converted = *reinterpret_cast<double*>(&words);
std::cout << hi << std::endl;
std::cout << lo << std::endl;
std::cout << converted << std::endl;
}
}
my program would operate in any platform
Included I assume those whose double format isn't IEEE. Something like this should work:
#include <math.h>
...
int const dbl_exponent_bits = 11;
int const dbl_exponent_offset = 1023;
int const dbl_significand_bits = 52;
bool negative = (*num++ == '1');
int exponent = 0;
for (int i = 0; i < dbl_exponent_bits; ++i, ++num) {
exponent = 2*exponent + (*num == '1' ? 1 : 0);
}
double significand = 1;
for (int i = 0; i < dbl_significand_bits; ++i, ++num) {
significand = 2*significand + (*num == '1' ? 1 : 0);
}
assert(*num == '\0');
double result = ldexp(significand, exponent-(dbl_exponent_offset+dbl_significand_bits));
if (negative)
result = -result;