A
A
Artyom_Kopan2021-10-29 14:59:48
C++ / C#
Artyom_Kopan, 2021-10-29 14:59:48

How to make such a feint with ears with double?

Based on the contents of the memory, output a double value in exponential form: sm*2^{Sp}, where s is the sign of the mantissa, m is the mantissa, S is the sign of the exponent, p is the exponent of the number.
Examples:
Enter a number: -2.5
Result: -1.25*2^1
Enter a number: 12312.323
Result: +1.5029691162109375384*2^13

I know how to do this algorithmically, but I need to fetch this representation from memory. I heard something about using union in this case and casting to int64_t, but I didn’t quite understand how to apply it

Answer the question

In order to leave comments, you need to log in

4 answer(s)
W
Wataru, 2021-10-29
@Artyom_Kopan

Use memcopy. Copy from the address of a double variable to the address of an int variable.
Tricks with union and pointer reinterpretation are quite dangerous.

M
Mercury13, 2021-10-29
@Mercury13

Why not? I write in C with crosses, but there is nothing specific there, except for a couple of reinsurances.
C++20 also introduced bit_cast.

#include <iostream>

union DoubleInt {
    double asDouble;
    uint64_t asInt;
};

static_assert(sizeof(double) == sizeof(uint64_t), "Strange machine with double != int64");

constexpr int BITS_MANTISSA = 52;
constexpr int BITS_EXPONENT = 11;
constexpr int BITS_SIGN = 1;

static_assert(BITS_MANTISSA + BITS_EXPONENT + BITS_SIGN == 64, "Programmer's funkup");

constexpr uint64_t MANTISSA_UNIT = uint64_t(1) << BITS_MANTISSA;
constexpr uint64_t MANTISSA_MASK = MANTISSA_UNIT - 1;

constexpr int EXPONENT_SHIFT = BITS_MANTISSA;
constexpr uint64_t EXPONENT_MAX = (uint64_t(1) << BITS_EXPONENT) - 1;
constexpr uint64_t EXPONENT_ORIGIN = EXPONENT_MAX >> 1;
constexpr uint64_t EXPONENT_MASK = EXPONENT_MAX << EXPONENT_SHIFT;
constexpr uint64_t EXPONENT_SHIFTED_ORIGIN = EXPONENT_ORIGIN << EXPONENT_SHIFT;

constexpr int SIGN_SHIFT = BITS_MANTISSA + BITS_EXPONENT;
constexpr uint64_t SIGN_MASK = uint64_t(1) << SIGN_SHIFT;

int main()
{
    DoubleInt x { -3.45 };

    // Простите уж, без денормализованных чисел

    // Оставим знак и мантиссу
    DoubleInt xMantissa = x;
    xMantissa.asInt &= (MANTISSA_MASK | SIGN_MASK);
    // И добавим туда стандартный нулевой порядок
    xMantissa.asInt |= EXPONENT_SHIFTED_ORIGIN;

    // Извлечём порядок
    int exponent = ((x.asInt & EXPONENT_MASK) >> EXPONENT_SHIFT) - EXPONENT_ORIGIN;

    std::cout << xMantissa.asDouble << "*2^" << exponent << std::endl;

    return 0;
}

U
User700, 2021-10-29
@User700

Something like this

union double_bitfld_t {
 double dbl;
 struct {
  unsigned int mnt : 52;
  unsigned int exp : 11;
  unsigned int sgn : 1;
 } bits;
};

double_bitfld_t x;
cin >> x.dbl;
cout << (x.bits.sgn ? '+' : '-') << (1+x.bits.mnt/double(1<<52)) << "*2^" << (x.bits.exp-1023) << endl;

Of course, you need to check, debug
Instead of "1+x.bits.mnt/double(1shift52)" it's better to create another variable as above and change the order to 0, getting the mantissa as double

T
Tony, 2021-10-29
@AntonSazonov

Read up on bit fields.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question