I'm trying to square every digit of a number, concatenate them and return the result as an integer.
For example, if I run 9191 through the function, 811181 will come out, because 9^2 is 81 and 1^2 is 1.
I made a function (don't even know if it's the most optimal, I'm quite new with the programming) so that the number gets converted into a string, then I loop through it, convert the single digit from a char back to a number and make the square of it. Then I save the new result in the form of a string, and concatenate it to another string that will be the final result.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 128
unsigned long long square_digits (unsigned n)
{
char n_str[MAX];
char c_str[MAX];
char s_result[MAX];
unsigned long long converted, result;
int i, len;
sprintf(n_str, "%u", n);
len = strlen(n_str);
s_result[0] = '\0';
for (i = 0; i < len; ++i)
{
converted = n_str[i] - '0';
converted = converted * converted;
sprintf(c_str, "%llu", converted);
strcat(s_result, c_str);
}
result = strtol(s_result, NULL, 10);
return result;
}
The tests are made through the following sequence of numbers:
unsigned long long square_digits (unsigned n);
#define do_test(n, expected) \
do { \
unsigned long long actual = square_digits(n); \
cr_assert_eq(actual, expected, "for n = %u, expected %llu, but got %llu", n, expected, actual);\
} while (false)
Test(test_suite, sample_tests)
{
do_test( 3212u, 9414ull);
do_test( 2112u, 4114ull);
do_test( 0u, 0ull);
do_test( 999u, 818181ull);
do_test( 10001u, 10001ull);
do_test(3210987654u, 9410816449362516ull);
do_test(3999999999u, 9818181818181818181ull); // :p
do_test( UINT_MAX, 164811681364948125ull);
}
First 6 tests are passed correctly, but then I got an unexpected result (the one with the ":p" comment).
sample_tests
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
for n = 3999999999, expected 9818181818181818181, but got 9223372036854775807
What is happening and how can I fix that? Is there another way to make this work?
9818181818181818181 is a 64-bit unsigned number with its most significant bit set.
OP's strtol(s_result, NULL, 10) is for signed conversion and 9818181818181818181 is outside its range. strtol() did the best it could and returned LONG_MAX, 9223372036854775807 or 0x7FFF_FFFF_FFFF_FFFF.
Use a matching conversion function: strtoull().
unsigned long long result;
...
// result = strtol(s_result, NULL, 10);
result = strtoull(s_result, NULL, 10);
More advanced code would check the conversion:
char *endptr;
errno = 0;
result = strtoull(s_result, &endptr, 10);
if (s_result == endptr || errno) {
puts("Trouble in conversion");
}
Related
I've been trying to print out the Binary representation of a long long integer using C Programming
My code is
#include<stdio.h>
#include <stdlib.h>
#include<limits.h>
int main()
{
long long number, binaryRepresentation = 0, baseOfOne = 1, remainder;
scanf("%lld", &number);
while(number > 0) {
remainder = number % 2;
binaryRepresentation = binaryRepresentation + remainder * baseOfOne;
baseOfOne *= 10;
number = number / 2;
}
printf("%lld\n", binaryRepresentation);
}
The above code works fine when I provide an input of 5 and fails when the number is 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
1.Test Case
5
101
2.Test Case
9223372036854775807
-1024819115206086201
Using a denary number to represent binary digits never ends particularly well: you'll be vulnerable to overflow for a surprisingly small input, and all subsequent arithmetic operations will be meaningless.
Another approach is to print the numbers out as you go, but using a recursive technique so you print the numbers in the reverse order to which they are processed:
#include <stdio.h>
unsigned long long output(unsigned long long n)
{
unsigned long long m = n ? output(n / 2) : 0;
printf("%d", (int)(n % 2));
return m;
}
int main()
{
unsigned long long number = 9223372036854775807;
output(number);
printf("\n");
}
Output:
0111111111111111111111111111111111111111111111111111111111111111
I've also changed the type to unsigned long long which has a better defined bit pattern, and % does strange things for negative numbers anyway.
Really though, all I'm doing here is abusing the stack as a way of storing what is really an array of zeros and ones.
As Bathsheba's answer states, you need more space than is
available if you use a decimal number to represent a bit sequence like that.
Since you intend to print the result, it's best to do that one bit at a time. We can do this by creating a mask with only the highest bit set. The magic to create this for any type is to complement a zero of that type to get an "all ones" number; we then subtract half of that (i.e. 1111.... - 0111....) to get only a single bit. We can then shift it rightwards along the number to determine the state of each bit in turn.
Here's a re-worked version using that logic, with the following other changes:
I use a separate function, returning (like printf) the number of characters printed.
I accept an unsigned value, as we were ignoring negative values anyway.
I process arguments from the command line - I tend to find that more convenient that having to type stuff on stdin.
#include <stdio.h>
#include <stdlib.h>
int print_binary(unsigned long long n)
{
int printed = 0;
/* ~ZERO - ~ZERO/2 is the value 1000... of ZERO's type */
for (unsigned long long mask = ~0ull - ~0ull/2; mask; mask /= 2) {
if (putc(n & mask ? '1' : '0', stdout) < 0)
return EOF;
else
++printed;
}
return printed;
}
int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i) {
print_binary(strtoull(argv[i], 0, 10));
puts("");
}
}
Exercises for the reader:
Avoid printing leading zeros (hint: either keep a boolean flag that indicates you've seen the first 1, or have a separate loop to shift the mask before printing). Don't forget to check that print_binary(0) still produces output!
Check for errors when using strtoull to convert the input values from decimal strings.
Adapt the function to write to a character array instead of stdout.
Just to spell out some of the comments, the simplest thing to do is use a char array to hold the binary digits. Also, when dealing with bits, the bit-wise operators are a little more clear. Otherwise, I've kept your basic code structure.
int main()
{
char bits[64];
int i = 0;
unsigned long long number; // note the "unsigned" type here which makes more sense
scanf("%lld", &number);
while (number > 0) {
bits[i++] = number & 1; // get the current bit
number >>= 1; // shift number right by 1 bit (divide by 2)
}
if ( i == 0 ) // The original number was 0!
printf("0");
for ( ; i > 0; i-- )
printf("%d", bits[i]); // or... putchar('0' + bits[i])
printf("\n");
}
I am not sure what you really want to achieve, but here is some code that prints the binary representation of a number (change the typedef to the integral type you want):
typedef int shift_t;
#define NBITS (sizeof(shift_t)*8)
void printnum(shift_t num, int nbits)
{
int k= (num&(1LL<<nbits))?1:0;
printf("%d",k);
if (nbits) printnum(num,nbits-1);
}
void test(void)
{
shift_t l;
l= -1;
printnum(l,NBITS-1);
printf("\n");
l= (1<<(NBITS-2));
printnum(l,NBITS-1);
printf("\n");
l= 5;
printnum(l,NBITS-1);
printf("\n");
}
If you don't mind to print the digits separately, you could use the following approach:
#include<stdio.h>
#include <stdlib.h>
#include<limits.h>
void bindigit(long long num);
int main()
{
long long number, binaryRepresentation = 0, baseOfOne = 1, remainder;
scanf("%lld", &number);
bindigit(number);
printf("\n");
}
void bindigit(long long num) {
int remainder;
if (num < 2LL) {
printf("%d",(int)num);
} else {
remainder = num % 2;
bindigit(num/2);
printf("%d",remainder);
}
}
Finally I tried a code myself with idea from your codes which worked,
#include<stdio.h>
#include<stdlib.h>
int main() {
unsigned long long number;
int binaryRepresentation[70], remainder, counter, count = 0;
scanf("%llu", &number);
while(number > 0) {
remainder = number % 2;
binaryRepresentation[count++] = remainder;
number = number / 2;
}
for(counter = count-1; counter >= 0; counter--) {
printf("%d", binaryRepresentation[counter]);
}
}
I'm making a C program to convert a decimal into a hexadecimal. My program seems to work fine for smaller numbers like 314156 stored in a long int but larger numbers such as 11806310474565 or 8526495043095935640 always return back 0x7FFFFFFF. How can I deal with or store numbers larger than 2147483647 / 2^32. I've tried using long long and unsigned long long, but those aren't working properly with my code.
code:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] ){
if(argc != 2 ){
printf("Usage: %s requires one parameter\n", argv [0]);
return 1;
}
unsigned long long decimal = atoi(argv[1]);
int count = 0, count2 = 0, value = decimal;
char hex[100];
for( ; value!=0 ; value/=10 )
count++;
unsigned long long q = decimal;
int i = 0, r = 0;
while( q != 0){
q = decimal/16;
r = decimal%16;
printf("%*llu = %*llu * 16 + %*d (%X)\n", count, decimal, count, q, 3, r, r);
hex[i++] = r<10 ? r+48 : r+55;
decimal = q;
}
printf("0x");
for(i-- ; i>=0; i--){
printf("%c",hex[i]);
}
printf("\n");
return 0;
}
I'm using gcc as a compiler.
You want atoll(), not atoi(). Read the documentation.
(Disclosure: I stopped reading your code at atoi.)
I've tried using long long and unsigned long long, but those aren't working properly with my code.
They require a different set of functions. If you use atoi to parse a very large number, you get MAX_INT value instead, explaining 0x7FFFFFFF output.
You need to replace the function by atoll:
unsigned long long decimal = atoll(argv[1]);
Note: Using "magic numbers" here
hex[i++] = r<10 ? r+48 : r+55;
is not ideal. It is better to write
hex[i++] = r<10 ? r+'0' : r+'A'-10;
or even
hex[i++] = "0123456789ABCDEF"[r];
Convert a string to an unsigned long long with strtoull(). #BLUEPIXY. atoll() fails when the result should be > LLONG_MAX.
unsigned long long decimal = strtoull(argv[1], (char **)NULL, 10);
Change type
unsigned long long decimal = ...;
// int value = decimal;
unsigned long long value = decimal;
Code has trouble with input "0". It just prints "0x"
Change
while( q != 0){
...
}
// to
do {
...
} while( q != 0);
--
For clarity, recommend
// hex[i++] = r<10 ? r+48 : r+55;
hex[i++] = r<10 ? r+'0' : r+'A'-10;
// or
hex[i++] = "0123456789ABCDEF"[r];
I am trying to convert number stored in the c string to long int. But I am not getting the expected output:
char str[] = "987654321012345";
long int num ;
num = 0;
//num = atol(str);
num = strtol(str, (char **) NULL, 10);
printf("%ld", num);
Output : 821493369
gcc version 4.4.7 20120313 (Red Hat 4.4.7-16)
Can you please advise what am I doing wrong here? Thanks.
In addition to using long long, you can use exact width types from stdint.h. For instance, to guarantee and 64-bit signed number you can use the int64_t type. Regardless what you do, do not cast NULL to char ** and always validate your conversions. E.g.,
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main (void) {
char str[] = "987654321012345";
long num = 0;
errno = 0;
num = strtol (str, NULL, 10);
if (errno) { /* validate strtol conversion */
perror ("strtol conversion failed.");
return 1;
}
printf ("%ld\n", num);
return 0;
}
Example Use/Output
$ ./bin/strtoltst
987654321012345
There are additional error checks you can do on the conversion, but at minimum, make sure errno is not set following your call to strtol or strtoll.
If you would like to use the guaranteed width types, then you can make the following changes:
...
#include <stdint.h>
...
int64_t num = 0;
...
num = strtoll (str, NULL, 10);
The result is the same.
I could reproduce and fix.
Code reproducing the problem
#include <stdio.h>
//#include <stdlib.h>
int main()
{
char str[] = "987654321012345";
long int num ;
char *ix;
num = 0;
//num = atol(str);
num = strtol(str, &ix, 10);
printf("%ld\n", num);
printf("%lu\n", sizeof(long));
return 0;
}
Gives as expected:
821493369
8
After a compilation warning
warning: implicit declaration of strtoll
Reason: as strtoll is undeclared, it is assumed to return an int, so the long value is first truncate to an int and than promoted back to a long.
Fix: just uncomment the #include <stdlib.h> line...
Conclusion: warnings are not meant to be ignored!
You should use long long as datatype for your number.
char str[] = "987654321012345";
long long num = strtoll(str, (char **)NULL, 10);
printf("%lld", num);
According to the C data type:
Long signed integer type. Capable of containing at least the [−2,147,483,647, +2,147,483,647] range; thus, it is at least 32 bits in size.
Long unsigned integer type. Capable of containing at least the [0, 4,294,967,295] range;
Is not enough, so you need a long long or unsigned long long and use %lli or %llu
"987654321012345" is too large.
Strol is outputing long type variable.
Long value is –2,147,483,648 to 2,147,483,647.
try
char str[] = "987654321012345";
char *pEnd;
long long num;
num = 0;
num = strtoull(str,&pEnd, 10);
printf("%lld", num);
return 0;
long long instead of long
strtoull instead of strtol
%lld instead of %ld
I am tring to convert hex to unsigned int from strtoul function. But I am getting output as ffffffff.
I have used stdlib.h library.
Can someone tell me at what part I am wrong?
void main()
{
char str1[33] = "88CC6069E4EDF969773369F988CC969F";
unsigned int hex_int;
hex_int = strtoul(str1, NULL, 16); //converting to unsigned int
printf("%x\n", hex_int);
}
C11 7.22.1.4p8:
The strtol, strtoll, strtoul, and strtoull functions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.
Try the following code:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char str1[] = "88CC6069E4EDF969773369F988CC969F";
errno = 0; // must reset errno first, otherwise it can retain an old value
unsigned long int hex_int = strtoul(str1, NULL, 16);
if (errno != 0) {
perror("strtoul failed:");
}
}
On my machine it will output
strtoul failed: Numerical result out of range
You make 2 mistakes: the value returned by strtoul is an unsignedlong; and even then, your value is 128 bits which is larger than the unsigned long on any common platform.
And also, do not bound the length of str1 - it should be at least 33 characters; or use a pointer-to-char instead:
char *str1 = "88CC6069E4EDF969773369F988CC969F";
And, int main(void).
Another manual version :
#include <ctype.h> // To use isdigit(), this function is not necessary if you can use ASCII table
const int asciiNumberBetweenDigitAndAlpha = 7; // see ASCII table
int str2[32];
const int size = sizeof(str1);
for (int i = 0; i < size - 1; i++)
{
if (isdigit(readLine[i]))
str2[i] = str1[i] - '0'; // In ASCII '0' = 48; '1' = 49..
else
str2[i] = str1[i] - '0' - asciiNumberBetweenDigitAndAlpha;
}
You could use, as an alternative to the ugly elsepart :
if (str1[i] == 'A')
str2[i] = 10;
else if (str1[i] == 'B')
str2[i] = 11;
...
use strtoull for larger numbers.
https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.bpxbd00/strtoull.htm
This is from google's code jam, practice problem "All your base".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long long pow_longlong(int digit, int raiseto)
{
if (raiseto == 0) return 1;
else return digit * pow_longlong(digit, raiseto - 1);
}
long long base10_with_map(int base, char* instr, char* digits)
{
if (base < 2) base = 2;
long long result = 0;
int len = strlen(instr);
int i = 0;
while (len--)
result += digits[instr[len]] * pow_longlong(base, i++);
return result;
}
long long test(char* in)
{
char appear[256];
int i;
int len = strlen(in);
int hold = 0;
for (i = 0; i < 256; i++) appear[i] = '\xFF';
for (i = 0; i < len; i++)
if (appear[in[i]] == '\xFF')
{
if (hold == 0) { appear[in[i]] = 1; hold++; }
else if (hold == 1) { appear[in[i]] = 0; hold++; }
else appear[in[i]] = hold++;
}
return base10_with_map(hold, in, appear);
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("Usage: %s <input-file> \n", argv[0]); return 1;
}
char buf[100];
int a, i;
FILE* f = fopen(argv[1], "r");
fscanf(f, "%d", &a);
long long result;
for (i = 1; i <= a; i++)
{
fscanf(f, "%s", buf);
result = test(buf);
printf("Case #%d: %lld\n", i, result);
}
return 0;
}
This works as intended and produces correct result to the problem. But if I replace my own pow_longlong() with pow() from math.h some calculations differ.
What is the reason to this? Just curious.
Edits:
- No overflow, plain long is enough to store the values, long long is just overkill
- Of course I include math.h
- In example: test("wontyouplaywithme") with pow_longlong returns 674293938766347782 (right) and with math.h 674293938766347904 (wrong)
Sorry that I won't go through your example and your intermediary function; the issue you're having occurs due to double being insufficient, not the long long. It is just that the number grows too large, causing it to require more and more precision towards the end, more than double can safely represent.
Here, try this really simple programme out, or just trust in the output I append to it to see what I mean:
#include <stdio.h>
int main( ){
double a;
long long b;
a = 674293938766347782.0;
b = a;
printf( "%f\n", a );
printf( "%lld", b );
getchar( );
return 0;
}
/*
Output:
674293938766347780.000000
674293938766347776
*/
You see, the double may have 8 bytes, just as much as the long long has, but it is designed so that it would also be able to hold non-integral values, which makes it less precise than long long can get in some cases like this one.
I don't know the exact specifics, but here, in MSDN it is said that its representation range is from -1.7e308 to +1.7e308 with (probably just on average) 15 digit precision.
So, if you are going to work with positive integers only, stick with your function. If you want to have an optimized version, check this one out: https://stackoverflow.com/a/101613/2736228
It makes use of the fact that, for example, while calculating x to the power 8, you can get away with 3 operations:
...
result = x * x; // x^2
result = result * result; // (x^2)^2 = x^4
result = result * result; // (x^4)^2 = x^8
...
Instead of dealing with 7 operations, multiplying them one by one.
pow (see reference) is not defined for integers, but only for floating point numbers. If you call pow with int as an argument the result will be a double.
You can in general not assume that the result of pow will be exactly the same as if you would use pure integer math as in the function pow_longlong.
Citation from wikipedia about double precision floating point numbers:
Between 2^52=4,503,599,627,370,496 and 2^53=9,007,199,254,740,992 the
representable numbers are exactly the integers. For the next range,
from 2^53 to 2^54, everything is multiplied by 2, so the representable
numbers are the even ones, etc.
So you get inaccurate results with pow if the result would be bigger than 2^53.