Converting a negative decimal into binary in C - c

I'm currently working on a program that (among others) has to convert a decimal number into binary, octal & hexadecimal.
This already works with this code:
int e = 0;
}
while(i != 0){
str[e] = (i%b) + '0';
i = i / b;
if(str[e] > '9'){
str[e] = str[e] + 7;
}
e++;
}
if(vorzeichen == -1){
str[e] = '1';
e++;
}
if(b == 16){
str[e] = 'x';
str[e+1] = '0';
}
else if(b == 8){
str[e] = '0';
}
}
b is the base (2 for binary, 8 for octal & 16 for hexa) and i is the number that i want to convert.
This gives out a string of characters which i then reverse to get the correct number. Now if i try this with negative numbers, it gives out strings not only containing 0 and 1 but also /, which is '0' -1 on the ASCII table. For octal and decimal it also gives out characters below the '/' on the ASCII table. I've attempted different possible solutions but none seemed to give the desired result. What I read on the internet is that I have to use the 2s Complement I'm stuck trying to use it. It just doesn't seem to work for me.

if you want to display a negative decimal you just can convert your int to a unsigned int like this :
unsigned int value = (unsigned int)i;
Now you only have to use value instead of i in your program and it will be fine.
Here's a good explanation of why : Converting negative decimal to binary

When converting between different bases/radixes, always work on unsigned integer types.
Let's say you have long num you wish to convert. Use an unsigned long u. To represent negative values in two's complement format, you can use
if (num < 0)
u = 1 + (~(unsigned long)(-num));
else
u = num;
or even shorter,
unsigned long u = (num < 0) ? 1 + (~(unsigned long)(-num)) : num;
This works on all architectures (except for num == LONG_MIN, in which case the above is technically undefined behaviour), even those that do not use two's complement internally, because we essentially convert the absolute value of num. If num was originally negative, we then do the two's complement to the unsigned value.
In a comment, chux suggested an alternative form which does not rely on UB for num == LONG_MIN (unless LONG_MAX == ULONG_MAX, which would be horribly odd thing to see):
unsigned long u = (num < 0) ? 1 + (~((unsigned long)(-1 - num) + 1)) : num;
This may look "uglier", but a sane C compiler should be able to optimize either one completely away on architectures with two's complement integers. chux's version avoids undefined behaviour by subtracting the negative num from -1, thus mapping -1 to 0, -2 to 1, and so on, ensuring that all negative values are representable as a nonnegative long. That value is then converted to unsigned long. This gets incremented by one, to account for the earlier -1. This procedure yields the correct negation of num.
In other words, to obtain the absolute value of a long, you can use
unsigned long abs_long(const long num)
{
return (num < 0) ? (unsigned long)(-1 - num) + 1u : (unsigned long)num;
}

% is the remainder function, not mod.
With b==2, i%b returns [-1, 0, 1]. This is not the needed functionality for str[e] = (i%b) + '0'; See ... difference between “mod” and “remainder”
This is the cause of '/' and "also gives out characters below the '/' ".
Build up the string from the "right"
With a 2's complement int, a simple approach is to convert to unsigned and avoid a negative result from %. Since code is using % to extract the least significant digit, walk the buffer from right to left.
#include <limits.h>
...
unsigned u = i;
// make a temporary buffer large enough for any string output in binary
// v------v Size of `u` in "bytes"
// | | v------v Size of a "byte" - commonly 8
char my_buff[sizeof u & CHAR_BIT + 1];
int e = 0;
// Form a pointer to the end so code assigns the least significant digits on the right
char *p = &my_buff[sizeof my_buff - 1];
// Strings are null character terminated
*p = '\0';
// Use a `do` loop to insure at least one pass. Useful when `i==0` --> "0"
do {
p--;
p[e] = "0123456789ABCDEF"[u%b]; // Select desired digit
u = u / b;
} while (u);
// "prepend" characters as desired
if(b == 16){
*(--p) = 'x';
*(--p) = '0';
}
else if(b == 8 && i != 0){
*(--p) = '0';
}
strcpy(str, p);

Related

Long to int truncation problem, truncating exceptions or handling error

Leetcode requires that the output of -91283472332 be converted to int, and the output result is -2147483648. I use long to store the result, and then return int. Why is the result returned -1089159116
here's my code
int myAtoi(char * s){
char *str = s;
long n = 0;
char *flag ;
while(*str){
if( * str =='-' || * str == '+')
{
flag = str++;
continue;
}
if(*str<='9' && *str>='0')
{
n*=10;
n+=(*str++)-48;
continue;
}
if(*str>='A'&&*str<='z')
break;
++str;
}
if(*flag == '-')
{
n-=(2*n);
}
return n;
}
So here's the description
Input: s = "-91283472332"
Output: -2147483648
Explanation:
Step 1:
"-91283472332" (no characters read because there is no leading whitespace)
^
Step 2:
"-91283472332" ('-' is read, so the result should be negative)
^
Step 3:
"-91283472332" ("91283472332" is read in)
^
The parsed integer is -91283472332.
Since -91283472332 is less than the lower bound of the range [-231, 231 - 1], the final result is clamped to -231 = -2147483648.
The value -91283472332 is 0xFFFFFFEABF14C034 in hexadecimal, two's complement.
When it is trunctated to 32-bit long, the value is 0xBF14C034 and it means -1089159116 when interpreted as two's complement.
You should add some conditional branch to return -2147483648 when the value exceeds the limit.
I guess you're doing this problem. Since it requires values outside the range to be clamped to the maximum values, A.K.A saturated math, you'll need to check the value's range like this
if (n > INT_MAX)
return INT_MAX;
else if (n < INT_MIN)
return INT_MINT;
else
return n;
It's similar to std::clamp(n, INT_MIN, INT_MAX) in C++
You can see that clearly in the requirements (emphasis mine):
If the integer is out of the 32-bit signed integer range [-231, 231 - 1], then clamp the integer so that it remains in the range. Specifically, integers less than -231 should be clamped to -231, and integers greater than 231 - 1 should be clamped to 231 - 1.
Now compare that with the above if blocks
If you cast the value from 64 to 32-bit then it'll reduce the value modulo 2n:
-91283472332 % 2147483648 = -1089159116,
or in hex: 0xFFFFFFEABF14C034 & 0xFFFFFFFF = 0xBF14C034
Saturation math is common in many areas like digital signal processing or computer graphics
is there a function in C or C++ to do "saturation" on an integer
How to do unsigned saturating addition in C?

Function for binary conversion

I am trying to convert a decimal value to binary using the function I wrote in C below. I cannot figure out the reason why it is printing 32 zeroes rather than the binary value of 2.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
int binaryConversion(int num){
int bin_buffer[32];
int mask = INT_MIN;
for(int i = 0; i < 32; i++){
if(num & mask){
bin_buffer[i] = 1;
mask >> 1;
}
else{
bin_buffer[i] = 0;
mask >> 1;
}
}
for(int j = 0; j < 32; j++){
printf("%d", bin_buffer[j]);
}
}
int main(){
binaryConversion(2);
}
Thanks
Two mistakes:
You use >> instead of >>=, so you're not actually ever changing mask.
You didn't declare mask as unsigned, so when you shift, it'll get sign-extended, which you don't want.
If you put a:
printf("%d %d\n", num, mask);
immediately inside your for loop, you'll see why:
2 -2147483648
2 -2147483648
2 -2147483648
2 -2147483648
:
2 -2147483648
The expression mask >> 1 does right shift the value of mask but doesn't actually assign it back to mask. I think you meant to use:
mask >>= 1;
On top of that (once you fix that problem), you'll see that the values in the mask are a bit strange because right-shifting a negative value can preserve the sign, meaning you will end up with multiple bits set.
You'd be better off using unsigned integers since the >> operator will act on them more in line with your expectations.
Additionally, there's little point in writing all those bits into a buffer just so you can print them out later. Unless you need to do some manipulation on the bits (and this appears to not be the case here), you can just output them directly as they're calculated (and get rid of the now unnecessary i variable).
So, taking all those points into account, you can greatly simplify your code such as with the following complete program:
#include <stdio.h>
#include <limits.h>
int binaryConversion(unsigned num) {
for (unsigned mask = (unsigned)INT_MIN; mask != 0; mask >>= 1)
putchar((num & mask) ? '1' : '0');
}
int main(void) {
binaryConversion(2);
putchar('\n');
}
And just one more note, the value of INT_MIN is not actually required to just have the top bit set. Because of the current allowance by C to handle ones' complement and sign-magnitude (as well as two's complement) for negative numbers, it possible for INT_MIN to have a value with multiple bits set (such as -32767).
There are moves afoot to remove these little-used encodings from C (C++20 has already flagged this) but, for maximum portability, you could opt instead for the following function:
int binaryConversion(unsigned int num) {
// Done once to set topBit.
static unsigned topBit = 0;
if (topBit == 0) {
topBit = 1;
while (topBit << 1 != 0) topBit <<= 1;
}
// Loop to process all bits.
for (unsigned mask = topBit; mask != 0; mask >>= 1)
putchar(num & mask ? '1' : '0');
}
This calculates the value with the top bit set the first time you call the function, irrespective of the vagaries of negative encodings. Just watch out if you call it concurrently in a threaded program.
But, as mentioned, this probably isn't necessary, the number of environments that use the other two encodings would be countable on the fingers of a very careless/unlucky industrial machine operator.
You already have your primary question answered regarding the use of >> rather than =>>. However, from a fundamental standpoint there is no need to buffer the 1 and 0 in an array of int (e.g. int bin_buffer[32];) and there is no need to use the variadic printf function to display int values if all you are doing is outputting the binary representation of the number.
Instead, all you need is putchar() to output '1' or '0' depending on whether any bit is set or clear. You can also make your output function a bit more useful by providing the size of the representation you want, e.g. a byte (8-bits), a word (16-bits), and so on.
For example, you could do:
#include <stdio.h>
#include <limits.h>
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
*/
void binaryConversion (const unsigned long v, size_t sz)
{
if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
if (!v) { while (sz--) putchar ('0'); return; }
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
int main(){
fputs ("byte : ", stdout);
binaryConversion (2, 8);
fputs ("\nword : ", stdout);
binaryConversion (2, 16);
putchar ('\n');
}
Which allows you to set the number of bits you want displayed, e.g.
Example Use/Output
$ ./bin/binaryconversion
byte : 00000010
word : 0000000000000010
There is nothing wrong with your approach, but there may be a simpler way to arrive at the same output.
Let me know if you have further questions.
INT_MIN is a negative number so when you shifted to the right using >>, the most significant bit will still be 1 instead of zero and you will end up in mask=11111...111 all bits have value of 1. Also the mask value is not changing. better use >>= instead. You can try masking on 0x1 and shift the actual value of num instead of the mask like this.
int binaryConversion(int num) {
char bin_buffer[32 + 1]; //+1 for string terminator.
int shifted = num;
for (int i = 31; i >= 0; --i, shifted >>= 1) { //loop 32x
bin_buffer[i] = '0' + (shifted & 0x1);
}
bin_buffer[32] = 0; //terminate the string.
printf("%s", bin_buffer);
}

Array contains garbage values not input values

I am writing a basic program to compute the binary eq of a decimal value. I'm storing the individual bits or 0 and 1 values into an array so I can eventually reverse the array and print the accurate binary representation. However when I print the array contents to check if array has been properly filled I see garbage values, or 0 if arr[]={0}
My code
int main() {
int i = 0, j = 0, k, decimal, binary = 0, remainder, divider;
int bin[10];
printf("Enter decimal value");
scanf("%d", &decimal);
while ((decimal != 0) && (i < decimal)) {
remainder = decimal % 2;
decimal = decimal / 2;
bin[i] = remainder;
j++;
printf("%d", bin[i]);
}
printf("\n%d", j);
printf("\n%d", bin[0]);
printf("\n%d", bin[1]);
printf("\n%d", bin[2]);
printf("\n%d", bin[3]);
printf("%d", bin);
return 0;
}
.exe
enter image description here
If you are still having problems with the conversion, it may be helpful to consider a couple of points. First, you are over-thinking the conversion from decimal to binary. For any given integer value, the value is already stored in memory in binary.
For example, when you have the integer 10, the computer stores it as 1010 in memory. So for all practical purposes, all you need to do is read the memory for value and set your array values to 1 for each bit that is 1 and 0 for each bit that is 0. You can even go one better, since what you are most likely after is the binary representation of the number, there is no need to store the 1s and 0s as a full 4-byte integer value in bin, why not make bin a character array and store the characters '1' or '0' in the character array (which when nul-terminated) allows a simple printing of the binary representation as a string.
This provides several benefits. Rather than converting from base 10 to base 2 and the divisions and modulo calls required for the base conversion, you can simply shift decimal to the right by one and check whether the least-significant-bit is 0 or 1 and store the desired character '0' or '1' based on the results of a simple unary and operation.
For example, in you case with an integer, you can determine the number of bits required to represent any integer value in binary with sizeof (int) * CHAR_BIT (where CHAR_BIT is a constant provided in limits.h and specifies the number of bits in a character (e.g. byte)). For an integer you could use:
#include <stdio.h>
#include <limits.h> /* for CHAR_BIT */
#define NBITS sizeof(int) * CHAR_BIT /* constant for bits in int */
To store the character representations of the binary number (or you could store the integers 1, 0 if desired), you can simply declare a character array:
char bin[NBITS + 1] = ""; /* declare storage for NBITS + 1 char */
char *p = bin + NBITS; /* initialize to the nul-terminating char */
(initialized to all zero and the +1 to allow for the nul-terminating character to allow the array to be treated as a string when filled)
Next, as you have discovered, whether you perform the base conversion or shift and and the resulting order of the individual bit values will be in reverse order. To handle that, you can simply declare a pointer pointing to the last character in your array and fill the array with 1s and 0s from the back toward the front.
Here too the character array/string representation makes things easier. Having initialized your array to all zero, you can start writing to your array beginning at the next to last character and working from the end to the beginning will insure you have a nul-terminated string when done. Further, regardless of the number of bits that make up decimal, you are always left with a pointer to the start of the binary representation.
Depending on how you loop over each bit in decimal, you may need to handle the case where decimal = 0; separately. (since you loop while there are bits in decimal, the loop won't execute if decimal = 0;) A simple if can handle the case and your else can simply loop over all bits in decimal:
if (decimal == 0) /* handle decimal == 0 separately */
*--p = '0';
else /* loop shifting decimal right by one until 0 */
for (; decimal && p > bin; decimal >>= 1)
*--p = (decimal & 1) ? '1' : '0'; /* decrement p and set
* char to '1' or '0' */
(note: since p was pointing to the nul-terminating character, you must decrement p with the pre-decrement operator (e.g. --p) before dereferencing and assigning the character or value)
All that remains is outputting your binary representation, and if done as above, it is a simple printf ("%s\n", p);. Putting all the pieces together, you could do something like the following:
#include <stdio.h>
#include <limits.h> /* for CHAR_BIT */
#define NBITS sizeof(int) * CHAR_BIT /* constant for bits in int */
int main (void) {
int decimal = 0;
char bin[NBITS + 1] = ""; /* declare storage for NBITS + 1 char */
char *p = bin + NBITS; /* initialize to the nul-terminating char */
printf ("enter a integer value: "); /* prompt for input */
if (scanf ("%d", &decimal) != 1) { /* validate ALL user input */
fputs ("error: invalid input.\n", stderr);
return 1;
}
if (decimal == 0) /* handle decimal == 0 separately */
*--p = '0';
else /* loop shifting decimal right by one until 0 */
for (; decimal && p > bin; decimal >>= 1)
*--p = (decimal & 1) ? '1' : '0'; /* decrement p and set
* char to '1' or '0' */
printf ("binary: %s\n", p); /* output the binary string */
return 0;
}
(note: the comment on validating ALL user input -- especially when using the scanf family of functions. Otherwise you can easily stray off into Undefined Behavior on an accidental entry of something that doesn't begin with a digit)
Example Use/Output
$ ./bin/int2bin
enter a integer value: 0
binary: 0
$ ./bin/int2bin
enter a integer value: 2
binary: 10
$ ./bin/int2bin
enter a integer value: 15
binary: 1111
Two's-complement of negative values:
$ ./bin/int2bin
enter a integer value: -15
binary: 11111111111111111111111111110001
Look things over and let me know if you have any questions, or if you really need bin to be an array of int. Having an integer array holding the individual bit values doesn't make a whole lot of sense, but if that is what you have to do, I'm happy to help.

In C, how am I able to use the printf() function to 'store' a string?

I am attempting to represent a bit16 representation of a number (floating point representation) using unsigned integers. The fraction field here deviates from the standard of 10, and is 8 bits - implying the exponent field is 7 bits and the sign is 1 bit.
The code I have is as follows:
bit16 float_16(bit16 sign, bit16 exp, bit16 frac) {
//make the sign the number before binary point, make the fraction binary.
//concatenate the sign then exponent then fraction
//
bit16 result;
int theExponent;
theExponent = exp + 63; // bias = 2^(7-1) + 1 = 2^6 + 1 = 63
//printf("%d",sign);
int c, k;
for(c = 6; c > 0; c--)
{
k = theExponent >> c;
if( k & 1)
printf("1");
else
printf("0");
}
for(c = 7; c >= 0; c--)
{
k = frac >> c;
if( k & 1)
printf("1");
else
printf("0");
}
//return result;
}
My thinking to 'recreate' a 16 bit sequence from these fields is to concatenate them together as so, but if I want to use them in a further application I am unable to do so. Is there a way to store the final result after everything has been printed (16-bit sequence) into a variable which can then be represented as an unsigned integer? Or is there a more optimal way to do this procedure?
While printf will not work in this case (you can't 'store' it's result), you can use sprintf.
int sprintf ( char * output_str, const char * format, ... );
sprintf writes formatted data to string
Composes a string with the same text that would be printed if format was used on printf, but instead of being printed (or displayed on the console), the content is stored as a C string in the buffer pointed by output_str.
The size of the buffer should be large enough to contain the entire resulting string. See Buffer Overflow.
A terminating null character (\0) will automatically be appended at the end of your output_str.
From output_str to an integer variable
You can use the atoi function to do this. You can get your answer in an integer variable like this:
int i = atoi (output_str);

Manually cast signed char

I'm working with some embedded hardware, a Rabbit SBC, which uses Dynamic C 9.
I'm using the microcontroller to read information from a digital compass sensor using one of its serial ports.
The sensor sends values to the microcontroller using a single signed byte. (-85 to 85)
When I receive this data, I am putting it into a char variable
This works fine for positive values, but when the sensor starts to send negative values, the reading jumps to 255, then works its way back down to 0. I presume this is because the last bit is being used to determine the negative/positive, and is skewing the real values.
My inital thought was to change my data type to a signed char.
However, the problem I have is that the version of Dynamic C on the Microcontroller I am using does not natively support signed char values, only unsigned.
I am wondering if there is a way to manually cast the data I receive into a signed value?
You just need to pull out your reference book and read how negative numbers are represented by your controller. The rest is just typing.
For example, two's complement is represented by taking the value mod 256, so you just need to adjust by the modulus.
int signed_from_unsignedchar(unsigned char c)
{
int result = c;
if (result >= 128) result -= 256;
return result;
}
One's complement is much simpler: You just flip the bits.
int signed_from_unsignedchar(unsigned char c)
{
int result = c;
if (result >= 128) result = -(int)(unsigned char)~c;
return result;
}
Sign-magnitude represents negative numbers by setting the high bit, so you just need to clear the bit and negate:
int signed_from_unsignedchar(unsigned char c)
{
int result = c;
if (result >= 128) result = -(result & 0x7F);
return result;
}
I think this is what you're after (assumes a 32-bit int and an 8-bit char):
unsigned char c = 255;
int i = ((int)(((unsigned int)c) << 24)) >> 24;
of course I'm assuming here that your platform does support signed integers, which may not be the case.
Signed and unsigned values are all just a bunch of bits, it is YOUR interpretation that makes them signed or unsigned. For example, if your hardware produces 2's complement, if you read 0xff, you can either interpret it as -1 or 255 but they are really the same number.
Now if you have only unsigned char at your disposal, you have to emulate the behavior of negative values with it.
For example:
c < 0
changes to
c > 127
Luckily, addition doesn't need change. Also subtraction is the same (check this I'm not 100% sure).
For multiplication for example, you need to check it yourself. First, in 2's complement, here's how you get the positive value of the number:
pos_c = ~neg_c+1
which is mathematically speaking 256-neg_c which congruent modulo 256 is simply -neg_c
Now let's say you want to multiply two numbers that are unsigned, but you want to interpret them as signed.
unsigned char abs_a = a, abs_b = b;
char final_sign = 0; // 0 for positive, 1 for negative
if (a > 128)
{
abs_a = ~a+1
final_sign = 1-final_sign;
}
if (b > 128)
{
abs_b = ~b+1
final_sign = 1-final_sign;
}
result = abs_a*abs_b;
if (sign == 1)
result = ~result+1;
You get the idea!
If your platform supports signed ints, check out some of the other answers.
If not, and the value is definitely between -85 and +85, and it is two's complement, add 85 to the input value and work out your program logic to interpret values between 0 and 170 so you don't have to mess with signed integers anymore.
If it's one's complement, try this:
if (x >= 128) {
x = 85 - (x ^ 0xff);
} else {
x = x + 85;
}
That will leave you with a value between 0 and 170 as well.
EDIT: Yes, there is also sign-magnitude. Then use the same code here but change the second line to x = 85 - (x & 0x7f).

Resources