Why does this program loop forever? - c

The goal of the program is to perform a checksum in the following way: multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2. If the total modulo 10 is 0, the number is valid The problem with my code is that it runs forever, therefore I suppose something is wrong with the loops, any suggestion on why that might be happening and how to fix it? Note:
#include <stdio.h>
#include <cs50.h>
#include <math.h>
double input(void);
int main(void)
{
double number = input();
double sum = 0;
double i = 1;
double current_digit;
do
{
current_digit = (fmod(number, pow(10,i)) - fmod(number, pow(10, i-1)))/pow(10, i-1); //formula to calculate the ith digit in a number
if (fmod(i,2) != 0)
{
sum += current_digit;
}
else
{
double second_number = 2*current_digit;
double j = 1;
do
{
double second_current_digit = (fmod(second_number, pow(10,j)) -fmod(second_number,pow(10, j-1)))/pow(10, j-1);
sum += second_current_digit;
j++;
}
while (fmod(second_number, pow(10,j)) == number);
i++;
}
}
while (fmod(number,pow(10, i)) != number);
if (fmod(sum,10) == 0)
{
printf("true");
}
else
{
printf("false");
}
}
double input(void)
{
double number = get_double("Number: ");
return number;
}

the usage of double ... the program will have to take in 16 digits or even more, I didn't know what to do to handle larger integers, maybe long type?
Most computers these days support 64-bit integers natively. Those can give you as many as floor(log_10(2^64)) = 19 decimal digits. If that's sufficient, use uint64_t from <stdint.h> (it's a type defined in the C standard).
If that's not sufficient, consider using an array of digits, or a more involved "big integer" data type, as in here.
Anyway, I'm betting the exact floating-point comparison is what's biting you, as, probably, the value of pow(10,i) is not an exact power of 10, so the fmod() changes number slightly. But - don't trust my guess, just use a debugger:
In a terminal: How to Debug C Program using gdb in 6 Simple Steps, or
In a graphic IDE: For example, Debugging C using Visual Studio Code on Linux.

Related

is there a way to use Arrays in this C problem?

I am doing this problem:
"We have a huge decimal number N. Write a program to determine the followings:
The number of digits in N.
Is N an even number?
The number of zeros in it.
Is N a multiple of 11? Note that we can determine if N is a multiple of 11 by checking the difference between the sum of the odd positioned digits and the sum of the even positioned digits. For example, 82375 is not a multiple of 11 because the sum of the even positioned digits is 2 + 7 = 9, and the sum of the odd positioned digits is 8 + 3 + 5 = 16, and the difference between 9 and 16 is 7, which is not a multiple of 11.
We will give you the number one digit per line. For example, if you get digits ‘1’, ‘2’, ‘3’, ’4’, ‘0’ in order, then the number is 12340. The number will not start with 0.
Input Format
The input has several lines. Each line has a digit. EOF indicates the end of input.
Output Format
Output the four answers above line by line. If the number is even output a 1; otherwise a 0. If the number is a multiple of 11 output a 1; otherwise output a 0.
Subtask
10 points: you can store the decimal number in an integer without overflow
10 points: the number of digits is no more than 32768, so you can store digits in an array
80 points: you will get MLE if you use array"
my code is:
#include <stdio.h>
#include <stdbool.h>
int digit(long n);
int is_even(int n);
int count_zeros(long n);
int is_multiple(long n);
int main() {
int digits = 0;
long x;
scanf("%ld", &x);
digit(x);
int even = is_even(x);
printf("%d\n", even);
printf("%ld\n",count_zeros(x));
printf("%ld\n", is_multiple(x));
}
int digit(long n)
{
int digits = 0;
while (n > 0) {
n /= 10;
digits++;
}
printf("%ld\n", digits);
}
int is_even(int n)
{
if (n % 2 == 0)
return true;
else
return false;
}
int count_zeros(long n)
{
int count = 0;
while (n > 0) {
n /= 10;
if (n %10 == 0)
count++;
}
return count;
}
int is_multiple(long n)
{
if (n % 11 == 0) {
return true;
}
else
return false;
}
Basically i dont know how to meet the problem's requirement, so I made a simpler version of the problem. Any clue on how to do this?
If you comment on this, please be nice, I am a beginner and people was rude in the past,if you have nothing important to say, do not be mean/do not comment.
Well, the first problem with your current version is it only reads one integer. However problem states that each digit is on a separate line. The first approach may be to just replace that scanf with a loop and keeping multiplying by 10 and accumulating until end of file. Then the rest of the program would work fine.
A more advanced approach will be to use an array to store the digits. An integer can hold a very limited number of digits whereas you are only bounded with the size of available memory using array.
So in the reading loop rather than storing digits in an integer, you can store digits in an array (which could be fixed size because an upper limit is given). But for the rest of the program you should change the calculation to use digits in the array instead of the regular integer arithmetic.

While loop ignores a boolean expression which compares two floating point variables

Edit:I solved the issue by first multiplying the float value by 100, then rounding it with roundf() function, then casting it to an integer to be stored in an integer variable. I did the remaining operations with integer values from there on and everything worked. Even though the solution offered by #JacobBoertjes actually worked, my assignment requiered me to use get_float() from the cs50.h library, so I didn't implement it. Here's the final code:
// Get user input as a positive float value
float f_change;
do {
printf("Change owed: ");
f_change = get_float();
} while(f_change < 0);
// Round & cast
int int_change = (int) roundf(f_change * 100);
My program accepts an amount of money, say $4.20, and figures out the least amount of coins with which it can represent this value. For example, desired output from the program with $4.20 as an input would be: 16 quarters ($4.00), 2 dimes ($0.20).My program successfully calculates the number of quarters, but fails to do so while working on dimes. The cause of this failure is the second for loop in the code. 0.10 >= 0.10 does not evaluate to true, so the last iteration of the loop never happens. What am I doing wrong? Here is the code. I provided test print statements with their outputs written as comments.
#include <stdio.h>
#include <cs50.h>
int main(void) {
// Fake user input
float owed_coin = 4.2f;
// Initialize coin variables
int coin_count = 0;
float quarters = 0.25f,
dimes = 0.10f;
// Calculate quarters
while(owed_coin >= quarters) {
owed_coin -= quarters;
coin_count += 1;
}
printf("owed_coin: %.2f\ncoin_count: %d\n\n", owed_coin, coin_count);
// Prints owed_coin: 0.20
// coin_count: 16
// Calculate dimes
while(owed_coin >= dimes) {
owed_coin -= dimes;
coin_count += 1;
}
printf("owed_coin: %.2f\ncoin_count: %d\n\n", owed_coin, coin_count);
// Prints owed_coin: 0.10
// coin_count: 17
}
Floating point comparison is generally a bad idea because floats often become non-exact and thus will not be exactly equal. As #bruceg mentioned, a good solution is to keep your monetary values in terms of cents, so that you avoid using a float.
You could replace float owed_coin = 4.2f; with int owed_coin = 420;
In terms of gathering user input into this number, here is my suggestion using scanf
int n1, n2;
printf("Please enter amount:");
scanf("%d.%2d", &n1, &n2);
owed_coin = n1*100 + n2;
Another solution allows you you keep your variables as floats, and just compare for a very small difference between the two. It can be found here: What's wrong with using == to compare floats in Java?
It uses the Java Math library, but a similar solution could look something like this in C:
while((owed_coin - dimes) >= -0.001) {
owed_coin -= dimes;
coin_count += 1;
}
If you want to learn more about why floating point numbers suffer small innacuracies then check this out: https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems

Integer to Binary Conversion Program Fails for Some Inputs

I wrote code for getting binary form of an integer. It works well for inputs like 1 or 10. However, it is failing for inputs like 256. (It gives 0000000 s output and misses the one).
#include <stdio.h>
#include <math.h>
int number_of_binary_digits_required(int n){
return ceil(log(n))+1;
}
void print_array(int * a, int n){
int i = 0;
for (;i<n;i++){
printf("%d\t", a[i]);
}
}
int main(){
int num = 256;
int binary[100];
int n = number_of_binary_digits_required(num);
int bin_digits = n-1;
while (num){
int temp = num%2;
num = num / 2;
binary[bin_digits] = temp;
//printf("%d\n", bin_digits);
bin_digits--;
}
print_array(binary, n);
//printf("%d", number_of_binary_digits_required(num));
//for(bin_digits = 0;bin_digits < number_of_binary_digits_required(num);bin_digits++)
//printf("%d",binary[bin_digits]);
}
Why is the issue coming and how to resolve it?
Thanks you!
C's log function gives result with a base of e, not 2. This is why some numbers give unexpected result in your program since you calculate using that. There is a function log2 which is what you need i think.
Your use of a logarithmic function to compute the number of digits in conjunction with ceil will suffer due to floating point undershoot.
A more reliable way of calculating the number of binary digits is to divide by two repeatedly until zero is attained.
The first mistake is to use log(n), which calculates log of n base e.
Instead use log2(n)
Hope it helps. :-)

Reversing a 5-digit number is the prog. and it is giving a wrong output

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int i,a,n,r;
n=12345;
r=0;
for(i=4;i>=0;i--)
{
a=n%10;
n=n/10;
r=r+a*pow(10,i);
}
printf("%d",r);
return 0;
}
Current output - 54320
Expected output - 54321
Please advise on what I may change in my code to reflect the correct output.
The pow function returns a value of type double. Because this is a floating point type, the result it returns will not always be exact.
What's happening in this case is that on the last iteration of the loop pow(10, 0) returns a value slightly less than 1. This results in the right hand side of r=r+a*pow(10,i); to similarly be slightly less than 54321. When this value is then assigned to r, which is of type int, it gets truncated.
Rather than using the pow function here, use the following:
r=r*10+a;
This shifts the current digits in r over by 1, then adds the newest digit to the end. Also, rather than using a for loop, use while (n>0) instead. Then it doesn't matter how many digits you have.
while (n>0)
{
a=n%10;
n=n/10;
r=r*10+a;
}
Here is a simplified version of your algorithm:
void reverse_digits(int a) {
int b = 0;
while (a > 0) {
b = b * 10 + a % 10;
a /= 10;
}
printf("%d\n", b);
}
As for converting to character arrays as mentioned in the comments it's worth to notice that the convertion function will do similar arithmetic operations in order to convert the integer to character array, so doing the reversing using integers seems more convenient.

Why am I getting this strange output on this simple C program? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am working on a personal project where one part of it deals with counting squares and cubes under a certain bound (in this case 10,000). So, I wrote a simple C program I thought would work to verify my results. Here is the little program I put together to see all of the cubes:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main() {
double i;
int cubes = 0;
for (i = 1; i < 10000; i++) {
if ( i == cbrt(i) * cbrt(i) * cbrt(i) ) {
printf("%f --- %f\n",i, cbrt(i));
cubes++;
}
}
printf("%i\n", cubes);
return 0;
}
I got the (incorrect) output : 24. If you want to look at this see the problem look at numbers 15 and 20 on the output. Why I am getting the wrong answer (the correct answer is 21) is an entirely different matter. My question arose when I was messing around with my code to try and fix this and I temporarily changed it to this:
int main() {
double i;
int cubes = 0;
for (i = 1; i < 10000; i++) {
double temp = (cbrt(i) * cbrt(i) * cbrt(i));
if ( i == temp ) {
printf("%f -> %f\n", i, temp);
cubes++;
}
}
printf("%i\n", cubes);
return 0;
}
Now, the program is printing every number between 1 and 9999. So, am I missing something ridiculously easy or what is going on? All I did was instead of having cbrt(i)*cbrt(i)*cbrt(i) in the if conditional I set a double variable equal to result and placed that in the conditional. Why is my program doing this?
I am not sure why this got down voted. I feel like this is a legitimate question. Sorry S.O. community...
double cbrt(double x) returns the closest representable cubic root of x.
The inexactness of the result, then cubed, may not exactly equal 'x' again.
Why 2nd program differs:
C is not obliged to perform double math only to double precision. It may use wider (long double). Depending on many things, the 2nd code appears to have done more in long double than the first. With the extra precision, its easy to see that the results, rounded to double appear exact.
C11dr §5.2.4.2.2 9 Except for assignment and cast (which remove all extra range and precision), the values yielded by operators with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type.
Why a typical program run (of either code) produces a result of about 3333.
Consider the double numbers from 2 to 4 and 8 to 64. double numbers are logarithmically distributed. There are as many different double from 2 to 4 as 8 to 16 as 16 to 32 as 32 to 64.
So now all 3 sets from 8 to 64 have a cube root of some answer in the 1 set of 2 to 4. Now if we cube the numbers 2 to 4, we get answers in the range 8 to 64. 1 set of numbers mapping into 3 sets. The round trip is not exact. See Pigeonhole principle. IOW: On average, 3 numbers in the range 8 to 64 have the same cubic root. Then the cube of that root will be 1 of the 3 original.
To find the count of the perfect integer cubes 0 to N
unsigned Perfect_Cube_Count(unsigned n) {
if (n == 0)
return 1;
unsigned i;
// overflow not possible
for (i = 0; i*i < n/i; i++);
return i;
}
Or
// valid for 0 <= x <= something_well_over_1e9
double Perfect_Cube_Count_d(double x) {
double y = cbrt(x);
return floor(y) + 1;
}
You probably want, as Andrew guessed, whole-number cube roots. Float math is quite tricky because of rounding errors. Generally you cannot rely on equality but must compare with an error margin.
To solve your problem though I'd construct the 21 cubes beforehand and then iterate over integers, comparing against the pre-constructed cubes. Or is that cheating? ;-)
In Samuel Becket's novel Watt there is a chapter about a Scottish "Math genius" who could in his head compute all integer third roots of integer cubes up to 10000 or so, too!
My uess, is your compiler does an optimization in the second case, eli inating cbrt calls. It just says the result of cbrt is strictly defined by the standard, so it might as well be always thte case that (i == temp)
You can twak this by some command line arguments, and force it to do exactly what is written in the code. As I recall, this should thhe default thing to do for C compilers regarding float arthimetic, but your compiler may think it is smarter than you or something.
EDIT
And yes, this code has nothing to do with finding perfect cubes...
EDIT
Totally not an answer to the question, but as a quick exercise, this I wrote this:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
static unsigned long count_cubes(unsigned long max_n)
{
unsigned long n = 1;
while (n*n*n <= max_n) {
++n;
}
return n-1;
}
int main(int argc, char **argv)
{
unsigned long max_n;
char *p;
if (argc < 2) {
return EXIT_FAILURE;
}
max_n = strtoul(argv[1], &p, 10);
if (max_n < 1 || max_n == ULONG_MAX) {
return EXIT_FAILURE;
}
printf("%lu\n", count_cubes(max_n));
return EXIT_SUCCESS;
}
Note: no need for floating point arithmetic
EDIT
Sorry, I really got into this...
This one can be a bit faster:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>
static unsigned long count_cubes(unsigned long max_n)
{
unsigned long n;
if (max_n < 256) {
n = 1;
}
else {
n = cbrtl(max_n) - 1;
}
while (n*n*n <= max_n) {
++n;
}
return n-1;
}
int main(int argc, char **argv)
{
unsigned long max_n;
char *p;
if (argc < 2) {
return EXIT_FAILURE;
}
max_n = strtoul(argv[1], &p, 10);
if (max_n < 1 || max_n == ULONG_MAX) {
return EXIT_FAILURE;
}
printf("%lu\n", count_cubes(max_n));
return EXIT_SUCCESS;
}
EDIT ( last time, I promise... )
To show an explanation of my little loop above, starting at cbrt(max_n)-1, I tried the one suggested by #chux , here are some results with slightly larger numbers:
PerfectCubes(18446724184312856125) == 2642246
which is fine but also
PerfectCubes(18446724184312856125-10) == 2642246
which is totally not fine, since 18446724184312856125 == 2642245^3 , meaning there are 2642245 perfect cubes <= 18446724184312856125-10 .
This also results from inaccuracies in floating point representation. You can try it for yourself, if your computer is somewhat similar to mine:
printf("%f\n", cbrt( 2642245UL * 2642245UL * 2642245UL));
/* prints 2642245.000000 */
printf("%f\n", cbrt( 2642245UL * 2642245UL * 2642245UL - 10UL));
/* prints 2642245.000000 */
These two numbers clearly don't have the same cubic root, yet cbrt returns the same results. In this case, floor doesn't help either. Anyways, one always needs to be very careful using floating point arithmetics. And now I really should go to sleep.

Resources