Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::binary(n)

14 views
Skip to first unread message

Alex Buell

unread,
May 30, 2006, 6:31:46 PM5/30/06
to
Here's something I put together just now; whilst I don't know enough
to make this act the same way std::hex and std::dec does, this works
quite well enough for me, but I think I could improve on this.
Suggestions and flames both welcome. To use, try this:

unsigned char ch = 0x80;
std::cout << std::binary(ch) << "\n";

So, here's the code as follows:

namespace std
{
template <typename _T>
struct _binary { std::string _digits; };

template <typename T>
inline _binary<T> binary(T n)
{
_binary<T> __binary;
int bits = sizeof(n);

switch (bits)
{
case 1 : bits = 7; break;
case 2 : bits = 15; break;
case 4 : bits = 31; break;
// add more if necessary
}

for (int i = bits; i >= 0; i--)
{
if ((n >> i) & 1)
__binary._digits.append("1");
else
__binary._digits.append("0");
}

return __binary;
}

template <typename T>
ostream& operator<<(ostream& stream, _binary<T> __binary)
{
stream << __binary._digits;
return stream;
}
}


--
http://www.munted.org.uk

Take a nap, it saves lives.

red floyd

unread,
May 30, 2006, 7:11:18 PM5/30/06
to
Alex Buell wrote:
> Here's something I put together just now; whilst I don't know enough
> to make this act the same way std::hex and std::dec does, this works
> quite well enough for me, but I think I could improve on this.
> Suggestions and flames both welcome. To use, try this:
>
You mean, other than the fact that you're adding to namespace std and
using identifiers reserved to the implementation under 17.4.3.1?

Alex Buell

unread,
May 31, 2006, 1:14:41 AM5/31/06
to
On Tue, 30 May 2006 23:11:18 GMT, I waved a wand and this message
magically appeared:

> > Here's something I put together just now; whilst I don't know enough
> > to make this act the same way std::hex and std::dec does, this works
> > quite well enough for me, but I think I could improve on this.
> > Suggestions and flames both welcome. To use, try this:
> >
> You mean, other than the fact that you're adding to namespace std and
> using identifiers reserved to the implementation under 17.4.3.1?

Umm, in which book and which edition would that be? If it's the C++
Programming Language book, 17.4.3 only relates to sets.

Alex Buell

unread,
May 31, 2006, 1:05:31 AM5/31/06
to
On Tue, 30 May 2006 23:11:18 GMT, I waved a wand and this message
magically appeared:

> > Here's something I put together just now; whilst I don't know enough


> > to make this act the same way std::hex and std::dec does, this works
> > quite well enough for me, but I think I could improve on this.
> > Suggestions and flames both welcome. To use, try this:
> >
> You mean, other than the fact that you're adding to namespace std and
> using identifiers reserved to the implementation under 17.4.3.1?

Good point, guess I should read up on 17.4.3.1.

boaz...@yahoo.com

unread,
May 31, 2006, 1:32:29 AM5/31/06
to
First do not add something to namespace std - this is only for standard
libs and your code not yet become part of the standard..
I think that first you have to consider that there is a standard
container for this - bitset.
second there are better ways (speed wise at least) that you can choose
in implementing this so I think that you have to rethink what you were
doing..
good luck anyways and take a nup :)

Kai-Uwe Bux

unread,
May 31, 2006, 1:43:50 AM5/31/06
to
Alex Buell wrote:

He was refering to the standard itself:

Adding to namespace std:

[17.4.3.1/1]
It is undefined for a C + + program to add declarations or definitions to
namespace std or namespaces within namespace std unless otherwise
specified. A program may add template specializations for any standard
library template to namespace std. Such a specialization (complete or
partial) of a standard library template results in undefined behavior
unless the declaration depends on a user-defined name of external linkage
and unless the specialization meets the standard library requirements for
the original template.


Reserved identifiers:

[17.4.3.1.2/1]
Certain sets of names and function signatures are always reserved to the
implementation:
? Each name that contains a double underscore (__) or begins with an
underscore followed by an uppercase letter (2.11) is reserved to the
implementation for any use.
? Each name that begins with an underscore is reserved to the implementation
for use as a name in the global namespace.


Best

Kai-Uwe Bux

Alex Buell

unread,
May 31, 2006, 2:05:42 AM5/31/06
to
On Wed, 31 May 2006 01:43:50 -0400, I waved a wand and this message
magically appeared:

> > Umm, in which book and which edition would that be? If it's the C++


> > Programming Language book, 17.4.3 only relates to sets.
>
> He was refering to the standard itself:

OK, thanks. I've now removed it from std namespace and put it in its
own namespace. But really we could do with something like std::bin. And
is there a way to have binary numbers? Something like:

unsigned char n = 01010101b;

Would be nice, but I'll make do with hex digits.

Luke Meyers

unread,
May 31, 2006, 11:20:23 AM5/31/06
to
Alex Buell wrote:
> template <typename _T>

Don't use identifiers with leading underscores -- those are reserved.

> struct _binary { std::string _digits; };
> template <typename T>
> inline _binary<T> binary(T n)
> {

Umm... why isn't all this work being done in a constructor?

> _binary<T> __binary;
> int bits = sizeof(n);

sizeof returns the size in characters (usu, but not alw, bytes), not
bits. Seems you already know this, based on your usage in the switch
statement, but it's a really bad idea to change the semantics of a
variable midstream like this. It's just confusing and misleading.

> switch (bits)
> {
> case 1 : bits = 7; break;
> case 2 : bits = 15; break;
> case 4 : bits = 31; break;
> // add more if necessary
> }

Ever think of making the computer compute this for you? They're good
at computing stuff. Also, all of these values are off by one, for no
apparent reason.

>
> for (int i = bits; i >= 0; i--)

Another piece of misleading code -- iterating backwards is unusual, and
the fact that you're doing it is easy to miss, which could lead to
unhappy surprises.

If your bit values weren't off by one, you could just do the far more
familiar:
for(int i = 0; i < bits; ++i)

> {
> if ((n >> i) & 1)

And then change this to
if (n & (1 << i))

> __binary._digits.append("1");
> else
> __binary._digits.append("0");
> }

I bet single quotes are faster here.

> template <typename T>
> ostream& operator<<(ostream& stream, _binary<T> __binary)

Pass by const&, not by value.

Luke

Alex Buell

unread,
May 31, 2006, 12:38:12 PM5/31/06
to
On 31 May 2006 08:20:23 -0700, I waved a wand and this message
magically appeared:

> Don't use identifiers with leading underscores -- those are reserved.

> Umm... why isn't all this work being done in a constructor?

> sizeof returns the size in characters (usu, but not alw, bytes), not


> bits. Seems you already know this, based on your usage in the switch
> statement, but it's a really bad idea to change the semantics of a
> variable midstream like this. It's just confusing and misleading.

> Ever think of making the computer compute this for you? They're good


> at computing stuff. Also, all of these values are off by one, for no
> apparent reason.

> Another piece of misleading code -- iterating backwards is unusual,


> and the fact that you're doing it is easy to miss, which could lead to
> unhappy surprises.

> If your bit values weren't off by one, you could just do the far more
> familiar:
> for(int i = 0; i < bits; ++i)

> And then change this to
> if (n & (1 << i))

> I bet single quotes are faster here.

> Pass by const&, not by value.

All this doesn't matter, I've switched to bitsets, as that's a lot
easier to work with.

Marcus Kwok

unread,
May 31, 2006, 1:23:14 PM5/31/06
to
Luke Meyers <n.luke...@gmail.com> wrote:
> sizeof returns the size in characters (usu, but not alw, bytes)

I thought by definition 1 char == 1 byte (though not necessarily
1 "octet" or 8 bits).

--
Marcus Kwok
Replace 'invalid' with 'net' to reply

Luke Meyers

unread,
May 31, 2006, 7:48:32 PM5/31/06
to
Marcus Kwok wrote:
> Luke Meyers <n.luke...@gmail.com> wrote:
> > sizeof returns the size in characters (usu, but not alw, bytes)
>
> I thought by definition 1 char == 1 byte (though not necessarily
> 1 "octet" or 8 bits).

I think the definition of "byte" is well-established (as 8 bits) and
well beyond the jurisdiction of the C++ standard.

Luke

Luke Meyers

unread,
May 31, 2006, 7:52:19 PM5/31/06
to
Alex Buell wrote:
> On 31 May 2006 08:20:23 -0700, I waved a wand and this message
> magically appeared:

Cute, but kind of defeats the purpose -- if you're going to quote me
(as you should when replying), I'd appreciate attribution.

> > Umm... why isn't all this work being done in a constructor?
>

> > Pass by const&, not by value.
>
> All this doesn't matter, I've switched to bitsets, as that's a lot
> easier to work with.

It's lovely that you've switched to bitsets, but I think I gave you
some very useful general C++ tips, so I'm a little dismayed to see you
simply assert that it "doesn't matter." Doing construction in
constructors, passing by const& to avoid expensive copying, writing
clear code, none of this is particular to the problem at hand. It's
just stuff you should do when writing C++.

Luke

Alf P. Steinbach

unread,
May 31, 2006, 8:20:15 PM5/31/06
to
* Luke Meyers:

Nope.

Some languages impose 8-bit bytes.

C and C++ do not. In the C++ standard, the result of sizeof is defined
as the number of bytes, and the size of char is defined as 1 (para
5.3.3/1). Which makes char and byte synonyms in C++. By implication,
since the C++ standard refers down to the C standard, a C++ byte is at
least 8 bits, and in practice all compilers for a given platform use the
same byte size. But a byte can be and is larger than 8 bits on some
systems, especially in the embedded systems world.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Alex Buell

unread,
May 31, 2006, 8:34:29 PM5/31/06
to
On 31 May 2006 16:52:19 -0700, I waved a wand and this message
magically appeared from Luke Meyers:

> > All this doesn't matter, I've switched to bitsets, as that's a lot
> > easier to work with.
>
> It's lovely that you've switched to bitsets, but I think I gave you
> some very useful general C++ tips, so I'm a little dismayed to see you
> simply assert that it "doesn't matter." Doing construction in
> constructors, passing by const& to avoid expensive copying, writing
> clear code, none of this is particular to the problem at hand. It's
> just stuff you should do when writing C++.

I've kept the file around; I'll work on it when I have the time.

Alex Buell

unread,
Jun 1, 2006, 5:49:15 AM6/1/06
to
On 31 May 2006 16:52:19 -0700, I waved a wand and this message
magically appeared from Luke Meyers:

> It's lovely that you've switched to bitsets, but I think I gave you
> some very useful general C++ tips, so I'm a little dismayed to see you
> simply assert that it "doesn't matter." Doing construction in
> constructors, passing by const& to avoid expensive copying, writing
> clear code, none of this is particular to the problem at hand. It's
> just stuff you should do when writing C++.

Right, here's my latest binary class:

class binary
{
public:
template <typename T>
binary(const T& n)
{
bits = sizeof(n) * 8;
for (int i = 0; i < bits; i++)
{


if (n & (1 << i))

digits.insert(digits.begin(), '1');
else
digits.insert(digits.begin(), '0');
}

if (digits.size() != bits)
throw;
}

friend std::ostream& operator<<(std::ostream& stream, const
binary& bin) {
stream << bin.digits;
return stream;
}

private:
std::string digits;
int bits;
};

Rod

unread,
Jun 1, 2006, 8:36:49 AM6/1/06
to
On Wed, 31 May 2006 07:05:42 +0100 Alex Buell <alex....@munted.org.uk> wrote:


:> is there a way to have binary numbers? Something like:


:>
:> unsigned char n = 01010101b;
:>
:> Would be nice, but I'll make do with hex digits.

std::bitset

Cheers,


__ Rod.

Luke Meyers

unread,
Jun 1, 2006, 4:21:10 PM6/1/06
to
Alex Buell wrote:
> Right, here's my latest binary class:

Hey, much better! Couple of suggested refinements inline, but really
just minor stuff...

> bits = sizeof(n) * 8;

If you want to avoid this magic number, and be portable to platforms
with char wider than 8 bits, there's a constant somewhere (in <limits>,
IIRC) which will give you the number of bits in a char.

> if (n & (1 << i))
> digits.insert(digits.begin(), '1');
> else
> digits.insert(digits.begin(), '0');

Same thing, less duplication:

digits.insert(digits.begin(), (n&(1<<i)) ? '1' : '0');

Or, for more readability, perhaps something like:

char const digit = (n & (1<<i))
? '1'
: '0';
digits.insert(digits.begin(), digit);

> if (digits.size() != bits)
> throw;

This is incorrect. You have to throw something. This syntax is only
for rethrowing an existing exception from within a catch block. The
reason the compiler doesn't catch it is because it can't tell whether
you'd actually be reaching this line from within a catch block farther
up the stack.

> friend std::ostream& operator<<(std::ostream& stream, const
> binary& bin) {
> stream << bin.digits;
> return stream;
> }

Or just:
return stream << bin.digits;

Cheers,
Luke

Alex Buell

unread,
Jun 1, 2006, 5:14:18 PM6/1/06
to
On 1 Jun 2006 13:21:10 -0700, I waved a wand and this message magically
appeared from Luke Meyers:

> If you want to avoid this magic number, and be portable to platforms


> with char wider than 8 bits, there's a constant somewhere (in
> <limits>, IIRC) which will give you the number of bits in a char.

Yep, it's std::numeric_limits<T>::digits. Thank the Ghods for that, as I
did wonder what I would have to do about architectures that may have
strange ideas about how many bits a type might have.

> Same thing, less duplication:
>
> digits.insert(digits.begin(), (n&(1<<i)) ? '1' : '0');

I've been using that a lot lately, didn't think of optimising that in
the code.

> > if (digits.size() != bits)
> > throw;
>
> This is incorrect. You have to throw something. This syntax is only
> for rethrowing an existing exception from within a catch block. The
> reason the compiler doesn't catch it is because it can't tell whether
> you'd actually be reaching this line from within a catch block farther
> up the stack.

I've implemented a class inherited from std::exception and throw an
exception if there's a mismatch between the bits and the number of
digits generated.



> Or just:
> return stream << bin.digits;

Hey, cool optimisation! Thanks. Below is the complete class:

class binary
{
public:
class bad_bits : public std::exception
{
virtual const char* what() const throw()
{
return "Number of Bits != Number of digits!";
}
} bad_bits;

template <typename T>
binary(const T& n)
{

bits = std::numeric_limits<T>::digits;


for (int i = 0; i < bits; i++)

digits.insert(digits.begin(), (n & (1 << i)) ?
'1' : '0');

if (digits.size() != bits)
throw bad_bits;
}

friend std::ostream& operator<<(std::ostream& stream, const
binary& bin) {

return stream << bin.digits;

Alex Buell

unread,
Jun 2, 2006, 2:52:05 AM6/2/06
to
On Thu, 1 Jun 2006 22:14:18 +0100, I waved a wand and this message
magically appeared from Alex Buell:

I've just done away with the need for the member variable 'bits' by
making it an const and moving it into the constructor.

#include <iostream>
#include <string>
#include <limits>
#include <exception>

class binary
{
public:
class bad_bits : public std::exception
{
virtual const char* what() const throw()
{
return "Number of Bits != Number of digits!";
}
} bad_bits;

template <typename T>
binary(const T& n)
{

const int bits = std::numeric_limits<T>::digits;


for (int i = 0; i < bits; i++)
digits.insert(digits.begin(), (n & (1 << i)) ?
'1' : '0');

if (digits.size() != bits)
throw bad_bits;
}

friend std::ostream& operator<<(std::ostream& stream, const
binary& bin) {
return stream << bin.digits;
}

private:
std::string digits;

0 new messages