Discussion:
unsigned integer to binary problem 16/32 problem
(too old to reply)
Test
2017-07-21 20:52:28 UTC
Permalink
I got a function that converts an unsigned int to binary string of ones and
zeroes:

void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}


for example if I do:

int_to_bin_digit(4157704578,32,myout);

.."myout" should have "11110111110100011000100110000010" (no zero at the end).

It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.

I tried to used unsigned long (which should be 32 bits wide on Arduino compiler:

void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}


Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.

What should I change?

---
This email has been checked for viruses by AVG.
http://www.avg.com
Rick C. Hodgin
2017-07-21 21:05:38 UTC
Permalink
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
You can find out if it's a size issue by using this:

void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << ((count/2)-1); //problem probably here
int i;
for (i = 0; i < count/2; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}

That will give you the first N/2 bits, and you can see if your initial
1U << (count-1) line was forcing the bit off the end.

You could also do this:
out[i] = (mask) ? '1' : '0';

And it would tell you if the mask value was 0, or if there was a bit
in there somewhere making it non-zero.

Thank you,
Rick C. Hodgin
Barry Schwarz
2017-07-21 21:22:07 UTC
Permalink
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
1U is a 16bit int. Shifting it 31 bits yields 0. Try using 1LU
instead.
Post by Test
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
The constant used to compute the initial value of mask
--
Remove del for email
James R. Kuyper
2017-07-21 21:39:07 UTC
Permalink
...
Post by Barry Schwarz
Post by Test
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
1U is a 16bit int. Shifting it 31 bits yields 0. Try using 1LU
"If the value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined." (6.5.7p3). "Undefined behavior" permits a result of 0, and
on many systems that's exactly what will happen. However, it also
permits other possibilities, such as filling the 16 bits of mask with
garbage picked up from the other 2 bytes of a 32-bit register.
Barry Schwarz
2017-07-22 04:40:14 UTC
Permalink
On Fri, 21 Jul 2017 17:39:07 -0400, "James R. Kuyper"
Post by James R. Kuyper
...
Post by Barry Schwarz
Post by Test
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
1U is a 16bit int. Shifting it 31 bits yields 0. Try using 1LU
"If the value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined." (6.5.7p3). "Undefined behavior" permits a result of 0, and
on many systems that's exactly what will happen. However, it also
permits other possibilities, such as filling the 16 bits of mask with
garbage picked up from the other 2 bytes of a 32-bit register.
The OP already confirmed the result was 0.
--
Remove del for email
James R. Kuyper
2017-07-22 19:14:24 UTC
Permalink
Post by Barry Schwarz
On Fri, 21 Jul 2017 17:39:07 -0400, "James R. Kuyper"
Post by James R. Kuyper
...
Post by Barry Schwarz
Post by Test
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
1U is a 16bit int. Shifting it 31 bits yields 0. Try using 1LU
"If the value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined." (6.5.7p3). "Undefined behavior" permits a result of 0, and
on many systems that's exactly what will happen. However, it also
permits other possibilities, such as filling the 16 bits of mask with
garbage picked up from the other 2 bytes of a 32-bit register.
The OP already confirmed the result was 0.
Yes, but your response incorrectly implied that he would be justified in
relying on that.
Test
2017-07-22 08:42:21 UTC
Permalink
Changing 1U to 1LU solved the problem.
Thanks everybody for helping out.
Post by Barry Schwarz
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
1U is a 16bit int. Shifting it 31 bits yields 0. Try using 1LU
instead.
Post by Test
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
The constant used to compute the initial value of mask
---
This email has been checked for viruses by AVG.
http://www.avg.com
Robert Wessel
2017-07-21 21:59:28 UTC
Permalink
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
to unsigned long, not unsigned *int*. So:

unsigned long mask = 1UL << (count-1)

BTW, you're probably better doing the conversion right-to-left
instead.

Something like:

void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;

for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
}
}
Barry Schwarz
2017-07-22 04:39:28 UTC
Permalink
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.

You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
--
Remove del for email
Robert Wessel
2017-07-22 05:58:52 UTC
Permalink
Post by Barry Schwarz
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.
You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
I meant to do a right shift of "in", not a left one. The idea is to
grab the low bit with the mask (so it's not variable), and the use the
shift to get to the next bit.
Pascal J. Bourguignon
2017-07-22 07:53:21 UTC
Permalink
Post by Robert Wessel
Post by Barry Schwarz
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.
You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
I meant to do a right shift of "in", not a left one. The idea is to
grab the low bit with the mask (so it's not variable), and the use the
shift to get to the next bit.
This is the usual thing to do, but this requires a buffer to store the
digits before reversing their order (or store in the buffer in the
reverse order as you do).

The buffer can be avoided if you keep shifting to the left as the OP.

One easy way to ensure it works whatever the size of the mask, is to use
the mask variable to compute the mask! Literal constants are bitches in
C… (as is everything else, it's incredible a language with so many
pitfalls and so few programmers really knowing it, has been able to
survive so long).

so:

-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Sat Jul 22 09:53:14

SRC="/tmp/m.c" ; echo ===== ; cat "$SRC" ; echo ===== ; EXE="m" ; gcc -I. -L. -g3 -ggdb3 -o ${EXE} ${SRC} && ./${EXE} && echo status = $?
=====
#include <stdio.h>
int main(){
unsigned int mask=0;
mask=~mask;
mask^=(mask>>1);
printf("mask = %x\n",mask);
return 0;
}

=====
mask = 80000000
status = 0

Compilation finished at Sat Jul 22 09:53:14
--
__Pascal J. Bourguignon
http://www.informatimago.com
Robert Wessel
2017-07-22 15:46:10 UTC
Permalink
On Sat, 22 Jul 2017 09:53:21 +0200, "Pascal J. Bourguignon"
Post by Pascal J. Bourguignon
Post by Robert Wessel
Post by Barry Schwarz
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.
You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
I meant to do a right shift of "in", not a left one. The idea is to
grab the low bit with the mask (so it's not variable), and the use the
shift to get to the next bit.
This is the usual thing to do, but this requires a buffer to store the
digits before reversing their order (or store in the buffer in the
reverse order as you do).
The buffer can be avoided if you keep shifting to the left as the OP.
The caller has provided the buffer, per the OP's specification.
Richard Heathfield
2017-07-22 09:25:16 UTC
Permalink
Post by Robert Wessel
Post by Barry Schwarz
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.
You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
I meant to do a right shift of "in", not a left one. The idea is to
grab the low bit with the mask (so it's not variable), and the use the
shift to get to the next bit.
Either way, an = sign would be handy at some point.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Robert Wessel
2017-07-22 15:44:51 UTC
Permalink
On Sat, 22 Jul 2017 10:25:16 +0100, Richard Heathfield
Post by Richard Heathfield
Post by Robert Wessel
Post by Barry Schwarz
On Fri, 21 Jul 2017 16:59:28 -0500, Robert Wessel
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of ones and
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The reason is that
mask gets zero and not 2147483648 as in the gcc version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
Shifting an unsigned value 1 bit to the left will guarantee the low
order bit is 0.
You probably meant to make the 0x01 a variable and shift it left.
Post by Robert Wessel
}
}
I meant to do a right shift of "in", not a left one. The idea is to
grab the low bit with the mask (so it's not variable), and the use the
shift to get to the next bit.
Either way, an = sign would be handy at some point.
Argh. I shall now go bang my head on the table for a while.
Tim Rentsch
2017-07-27 10:36:30 UTC
Permalink
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The
reason is that mask gets zero and not 2147483648 as in the gcc
version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
}
}
What metric do you mean for "better"? To me writing the bits
left-to-right seems easier to understand:

void
int_to_bin_digit( unsigned long in, int k, char * out ){
while( k-- > 0 ) *out++ = '0' + (in >>k &1);
*out = 0; // yes I am null terminating the string :)
}
Robert Wessel
2017-07-27 17:14:18 UTC
Permalink
On Thu, 27 Jul 2017 03:36:30 -0700, Tim Rentsch
Post by Tim Rentsch
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The
reason is that mask gets zero and not 2147483648 as in the gcc
version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
}
}
What metric do you mean for "better"?
Well, there's always the "I liked it better" standard...
Post by Tim Rentsch
To me writing the bits
void
int_to_bin_digit( unsigned long in, int k, char * out ){
while( k-- > 0 ) *out++ = '0' + (in >>k &1);
*out = 0; // yes I am null terminating the string :)
}
If you know the number of output digits, you can do the operation
without a variable digit selection process. In this case you've
replaces a required variable shift in the left-to-right routine with a
fixed shift in the right-to-left routine. For binary that's not too
bad on many machine (although it would be unlikely to ever be faster
than a fixed shift), but it turns pretty ugly if you were doing this
in a non-power-of-two base.

As a minor advantage, the right-to-left approach also works correctly
if the number of digits specified by the caller exceeds the number of
bits in an unsigned long.

Of course assuming I hadn't made two significant errors on the shift
line in my original code...
Tim Rentsch
2017-07-28 08:53:43 UTC
Permalink
Post by Robert Wessel
On Thu, 27 Jul 2017 03:36:30 -0700, Tim Rentsch
Post by Tim Rentsch
Post by Robert Wessel
Post by Test
I got a function that converts an unsigned int to binary string of
void int_to_bin_digit(unsigned int in, int count, char * out)
{
unsigned int mask = 1U << (count-1);
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
int_to_bin_digit(4157704578,32,myout);
.."myout" should have "11110111110100011000100110000010" (no zero at the end).
It works fine on compiled wuth gcc. I am converting it to work on an Arduino
where "int" is 16 bit wide - not 32.
void int_to_bin_digit(unsigned long in, int count, char * out)
{
unsigned long mask = 1U << (count-1); //problem probably here
int i;
for (i = 0; i < count; i++)
{
out[i] = (in & mask) ? '1' : '0';
in <<= 1;
}
}
Unfortunately I get just "00000000000000000000000000000000". The
reason is that mask gets zero and not 2147483648 as in the gcc
version.
What should I change?
Probably you need to change the type of the 1 literal you're shifting
unsigned long mask = 1UL << (count-1)
BTW, you're probably better doing the conversion right-to-left
instead.
void int_to_bin_digit(unsigned long in, int count, char * out)
{ /* not tested, etc. */
int i;
for (i=0; i<count; i++)
{
out[count-i-1] = '0' + (in & 0x01);
in << 1;
}
}
What metric do you mean for "better"?
Well, there's always the "I liked it better" standard...
Post by Tim Rentsch
To me writing the bits
void
int_to_bin_digit( unsigned long in, int k, char * out ){
while( k-- > 0 ) *out++ = '0' + (in >>k &1);
*out = 0; // yes I am null terminating the string :)
}
If you know the number of output digits, you can do the operation
without a variable digit selection process. In this case you've
replaces a required variable shift in the left-to-right routine with a
fixed shift in the right-to-left routine. For binary that's not too
bad on many machine (although it would be unlikely to ever be faster
than a fixed shift), but it turns pretty ugly if you were doing this
in a non-power-of-two base.
Yes on all those (although the variable shifts can be replaced by
one variable shift and then constant shifts inside the loop).

Besides being easier to understand, the left-to-right method
appeals to me because it feels less brittle - no worries about
the index calculation or falling off the bottom of the output
space.
Post by Robert Wessel
As a minor advantage, the right-to-left approach also works correctly
if the number of digits specified by the caller exceeds the number of
bits in an unsigned long.
Yes, assuming of course that what is wanted is zeroes. It might be
better to use spaces for positions that fall outside the width of
the parameter type. And it's easy to write a short while() loop
for the L-to-R version (although it does take knowing what the
width of the parameter data type is, which isn't terribly hard,
but it isn't as easy as falling off a log either).
Post by Robert Wessel
Of course assuming I hadn't made two significant errors on the shift
line in my original code...
I discounted those.

Sometime I should show you the code I wrote to print 64-bit
integers, in decimal, from left to right. That should be
good for a laugh.
Richard Heathfield
2017-07-28 11:00:34 UTC
Permalink
Post by Tim Rentsch
And it's easy to write a short while() loop
for the L-to-R version (although it does take knowing what the
width of the parameter data type is, which isn't terribly hard,
but it isn't as easy as falling off a log either).
I didn't quite LOL at that but, if it's any consolation, I did LOQ.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
I am of course assuming that the pun was intentional.
Loading...