TransWikia.com

type casting boost multiprecision integer returns wrong answer

Stack Overflow Asked by amritkrs on December 3, 2020

The issue I am facing is with boost multiprecision cpp_int type casting to a small integer type int16_t.
Typecasting unsigned integer value of 43690 to int16_t is supposed to return -21846, however what I am getting is 32767. Am I missing anything here?

Here is the sample snippet of code to reproduce the behavior

#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
typedef boost::multiprecision::uint128_t uint_xt;
using namespace std;
int main() {
    uint_xt a = 43690;
    uint64_t c = 43690;
    int16_t b = static_cast<int16_t>(a);
    int16_t d =  static_cast<int16_t>(c);
    cout << b << ", " << d << endl;
    return 0;

}

Output: 32767, -21846

Edit: The issue lies with implementation defined behavior of cast in case of overflow.Efficient unsigned-to-signed cast avoiding implementation-defined behavior seems to have an answer for this.

2 Answers

Let's consider this line first:

int16_t d =  static_cast<int16_t>(c);

This follows the conv.integral#3 clause of the C++ Standard about integer conversions between builtin types:

Otherwise [i.e. the destination type is not bool], the result is the unique value of the destination type that is congruent to the source integer modulo 2N, where N is the width of the destination type.

Now to this line:

int16_t b = static_cast<int16_t>(a);

This follows the Boost implementation of the handling of conversion overflow in boost::multiprecision::backends::eval_convert_to, defined in boost/multiprecision/cpp_int/misc.hpp:

/*<return type skipped>*/
   eval_convert_to(R* result, const cpp_int_backend</*skipped*/>& val)
{
   typedef typename /*<skipped>*/ common_type;
   if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
   {
      conversion_overflow(/*<arguments skipped>*/);
      *result = (std::numeric_limits<R>::max)();
   }
   else
      *result = static_cast<R>(*val.limbs());
}

As you can see, the result returned is the maximum value for the target type, which is not what the compiler is doing for the built-in types. But it's not wrong, it's just a bit unexpected.

Correct answer by Ruslan on December 3, 2020

you basically try to convert int 128 & 64 to 16 for example :

sizeof int16_t = 2B
sizeof int64_t = 8B

& you want to convert something with 8B in size to 2B basically what you get it's a wrong values even you use C style.

to avoid this problems you should care about sizes when you deal with datatypes for example :

uint64_t  c = 43690;
int64_t d = (int64_t)(c);

Answered by ouchane.exe on December 3, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP