0

I am not even sure if my title is accurate, but for my project, I need to take a double and convert it into a hexadecimal and then convert it back to a double. But in order to do that, I think I would need to overload the operator << before I can output the answer. This is what I have so far, but I get prompted that "no operator "<<" match these operands"> Could someone please point me in the right direction of how I should overload the << operator in main? Thank you!

#include <iostream>
#include <iomanip>
#include <cstdint>

using namespace std;

void out_char_as_hex(int c)
{
    cout << hex << setw(2) << setfill('0') << c;
}


int main()
{
    union { double d; uint64_t u; } tmp;
    double x = -0.15625;
    tmp.d = x;

    cout << out_char_as_hex(tmp.d) << endl;

    return 0;
}

if it helps this is the question "If x is a variable of type double, it binary representation can be re-interpreted as a 64 bits integer, which can be represented exactly. To do that, you can either get the memory address to the variable of type double and reinterpret cast it to a 64-bit int pointer or use a union. To make the textual representation more compact, we use base 16 (hexadecimal). For example, the double number -0.15625 should be saved to file as the sequence of 16 characters bfc4000000000000 (see example in DemoHex.cpp, which use a union). When reading, you need to read the integer number saved in hexadecimal format and re-interpret it as a double. You need to modify the implementation of the operator<< for double and implement the overload of the operator>>"

Bert
  • 1
  • 3
  • 5
    You "can't" use a union. type punning through a union in C++ is illegal. – NathanOliver Oct 10 '17 at 14:04
  • Perhaps I'm missing something, but the question doesn't make sense to me. There is no hex representation of floating point values. Can you write some expected input/output? – AndyG Oct 10 '17 at 14:06
  • Hi Nathan thanks for your reply. The project that I have requires me to use the union function though, so the prof requires us to overload the << operator to get it to work. Any idea on this? – Bert Oct 10 '17 at 14:07
  • Hi Andy for example, for -0.15625 it would be saved as bfc4000000000000 in hexademical. Then convert it back to a double using the out_char_as_hex function. Sorry, that's my interpretation of the question. I'm pretty new to C++, so pls forgive me if my terminologies are wrong – Bert Oct 10 '17 at 14:12
  • 2
    If you drop the "using union" requirement it is possible to get this to work without undefined behavior by using `memcpy`. – nwp Oct 10 '17 at 14:14
  • BTW, you don't actually use union here. – Jarod42 Oct 10 '17 at 14:15
  • Hi all, in the question statement it specifically states that we would need to use either "reinterpret_cast" or "union" – Bert Oct 10 '17 at 14:20
  • @Bert Some compiler formally support this use of `union` as an extension. Check with your teacher what compiler this is supposed to work on. If the compiler has this extension, the code would be legal for that compiler despite not being legal standard c++. Note that `reinterpret_cast` is just as wrong as `union` for this purpose, and I suspect fewer compilers (if any) would formally support this use of it. If your teacher is teaching undefined behavior as standard c++, I would be wary of anything else he might be teaching... – François Andrieux Oct 10 '17 at 14:30
  • _you can **either** get the memory address to the variable of type double and reinterpret cast it to a 64-bit int pointer **or** use a union_ Why not try the first method? – 001 Oct 10 '17 at 14:42
  • @FrançoisAndrieux i'm not really sure which compiler this is supposed to work on, but we were told to use microsoft visual studio. This was supposed to be an introductory module on C++. I'm very new to C++ (few weeks into my first C++ lecture). Just wondering, is this considered as basic in C++? – Bert Oct 10 '17 at 14:43
  • @JohnnyMopp I believe the reinterpret cast is the alternative method to the union which the prof suggested. But I'm not really sure how to get started on that. For the reinterpret cast method, would you know how the operator << be overloaded? – Bert Oct 10 '17 at 14:48
  • 1
    I don't consider this to be basic C++ even though in the C days, people wanted to use these tricks as soon as possible. Primitives/std::string/iostream/main, loop/branch, class/function, containers (std::vector), header/source files first. iterators/algorithms/lambdas, inheritance/polymorphism, basic templates second, casting and byte representation really belong after that. – stefaanv Oct 10 '17 at 14:55
  • 1
    It seems your professor doesn't really know C++ well enough to teach it. Unfortunately that is no exception, that is the norm. Take everything you learn there with a good portion of skepticism and [read a book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282) if you actually want to learn C++. – nwp Oct 10 '17 at 14:58
  • `double g = -0.15625; cout << hex << *(reinterpret_cast(&g));` – 001 Oct 10 '17 at 15:08
  • @JohnnyMopp thanks! – Bert Oct 10 '17 at 15:21

2 Answers2

2

This is a version that doesn't use a union, but instead copies the bit pattern from a double to a uint64_t.

Assuming that this bit pattern is valid for an integer, the copying should be valid too. And it also produces the expected output.

#include <iostream>
#include <iomanip>
#include <cstdint>

using namespace std;

void out_char_as_hex(std::uint64_t c)
{
    cout << hex << setw(16) << setfill('0') << c << endl;
}


int main()
{
    uint64_t u;
    double x = -0.15625;

    std::memcpy(&u, &x, sizeof(u));

    out_char_as_hex(u);

    return 0;
}

However, this isn't the solution the professor has requested, so probably "wrong".

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • I've never heard of an invalid bit-pattern for integers and I know each pattern from 0x0000... to 0xFFFF... ;) . Care to explain? Or did you mean patterns that don't fit in a given integer? – stefaanv Oct 10 '17 at 14:35
  • @Bo Persson thanks for your help! but i don't think i am able to use your solution – Bert Oct 10 '17 at 14:37
  • 1
    @stefaanv - There used to be odd machines where not *every* bit pattern is a valid value. Some invalid values just might generate a trap. None of those machines are likely to have a `uint64_t` type though. (Just wanted to preempt comments about possible undefined behavior here as well.) – Bo Persson Oct 10 '17 at 14:41
  • Nice to know. I've never had the "pleasure" of working with these. Strictly multiple of 8bits, 2's complement CPU's for me, even for DSP's. – stefaanv Oct 10 '17 at 14:44
0

If conversion is just for printing then you don't need to overload any operator. Using io manipulator 'std::hexfloat' you can print float in hexdecimal.

Based on you example code and explanation, I think you are trying to do something as follows

#include <iostream>
#include <iomanip>

union test
{
    double x;
    uint64_t y;
};

// Insertion operator is overloaded to take union and 
// print uint64_t value from it.  
std::ostream & operator << (std::ostream &out, const test &t)
{
    out << std::hex << std::setw(50) << std::setfill('0') << t.y;
    return out;
}

int main()
{
    test t;
    t.x = -0.15625;
    std::cout << t << std::endl;    
    return 0;
}

Whatever is printed here is a bit pattern that is used to store float number in memory (sign bit, exponent and mantissa).

UPDATE: Above code will result into undefined behavior as we are NOT reading from most recently written member(Reference: http://en.cppreference.com/w/cpp/language/union)

Here is an alternate way of doing it without using union.

#include <iostream>
#include <iomanip>

struct test
{
    double x;
};

std::ostream & operator << (std::ostream &out, test &t)
{
    uint64_t *y = reinterpret_cast<uint64_t *>(&t.x);
    out << std::hex << std::setw(50) << std::setfill('0') << *y;
    return out;
}

int main()
{
    test t;
    t.x = -0.15625;
    std::cout << t << std::endl;
    return 0;
}
nyemul
  • 71
  • 5
  • Hi Nyemul, thanks for your help! It does seem to be something which I need. I'll try to digest it! Just to clarify, that means the "<<" operator is not needed if printing is just required? But I think we would need to do the conversion and store them too. Probably that's why we need to overload it? Thanks a lot! – Bert Oct 10 '17 at 16:38
  • You need not to overload insertion (<<) operator neither for printing nor for conversion. Operator overloading is needed if you want the operator to do anything more with user defined type. Internally, all numbers are stored as binary, so how you are planning to store hex number? – nyemul Oct 10 '17 at 16:45
  • This answer shares a problem with an earlier, now deleted, answer. You are writing to one member of the union and then reading from the other member. In C this is well defined, but in C++ it is formally undefined. From http://en.cppreference.com/w/cpp/language/union *" it's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union."* So it might work, but is non-standard. That's also why I wrote a non-union answer. – Bo Persson Oct 10 '17 at 22:40
  • BoPersson Thanks for pointing it. But that means we can not use unions in C++ the way it was used in C. @Bert be cautious using the above suggestion – nyemul Oct 11 '17 at 02:51
  • Hi all, thank you very much for all the help! It has helped me to at least start understanding and working towards the right direction for the project. Cheers! – Bert Oct 12 '17 at 14:41