I've recently started an online course in C, and am working through the second question in PS1. The question requires us to request an input of change from a user in dollars, and to calculate the smallest number of coins you can give them that change with, provided you are only allowed 25 cent, 10 cent, 5 cent and 1 cent coins.
For example 50 cents would be 2 25 cent coins, and 65 cents would be 2 25 cent coins, 1 10 cent coin and 1 5 cent coin.
Here is my code:
#include <stdio.h>
#include <cs50.h>
int main(void)
{
float change = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
int remainder3 = 0;
.
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
//converts amount in dollars to cents
change = change*100;
//We want to use the largest number of big cois as possible to make up the change.
// This calculates the remainder (if any) after dividing the change by 25. % = modulo, only works with integer operands.
remainder = (int)change % 25;
//(change - remainder) gets us the largest number divisible by 25. This line then calculates
// the maximum number of 25cent coins we can use, and sets this number equal to the coinCounter.
coinCounter = ((int)change - remainder)/25;
//Finds the remainder (if any) when dividing the last remainder by 10.
remainder1 = remainder % 10;
//(remainder - remainder1) gets us the largest number divisible by 10. Dividing this by 10, we
// determine the max amount of 10 cent coins we can use to make up the required change. We then add
// this number of coins to the total coinCounter.
coinCounter = coinCounter + ((remainder - remainder1)/10);
//Again, take the remainder (if any) from the last calculation, and find the remainder when dividing by 5.
remainder2 = remainder1 % 5;
// (remainder1 - remainder2)/5 tells us the number of 5 cent coins we need to make up the required change.
// We add the number of coins to the coin counter.
coinCounter = coinCounter + ((remainder1 - remainder2)/5);
//Finds the remainder when dividing last remainder by 1. There will actually be no remainder, so remainder 3 will
// equal zero.
remainder3 = remainder2 % 1;
//Here, (remainder2 - remainder1)/1 Finds the number of 1 cent coins required to make up the left change.
// remainder3 will always be zero. Hence (remainder2)/1 will always be equal to remainder 2. We add this number
// of 1 cent coins to the coinCounter.
coinCounter = coinCounter + ((remainder2 - remainder3)/1);
//We print out coinCounter, which is the smallest number of coins required to make up the change.
printf("%i\n",coinCounter);
}
Now I am new to programming, so I am very aware that there are probably far more efficient ways of tackling this problem. However, this seems to work fairly well. However, strangely, I get an incorrect result when I try '4.2'. I should get 18 coins (16 25 cent coins and 2 10 cent coins), however the program displays 22. It works well for all other numbers I have tried however.
I cannot figure out what I have done wrong. I feel like it either has something to do with where I change dollars to cents by multiplying by 100, OR, where I calculate the modulo and cast change to an int, but I unfortunately cannot figure it out alone.
I have heavily annotated my code so it is somewhat easier to understand. I hope someone can help me with this!
I would do something simpler, like:
int main(void)
{
float change = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
change = change*100;
coinCounter = (int)change/25; //number of 25cents
remainder = change % 25; //rest
if(remainder > 0){
coinCounter += (int)remainder/10; //number of 10cts
remainder1 = remainder%10;
}
if(remainder1 > 0){
coinCounter += (int)remainder1/5; //number of 5cts
remainder2 = remainder1%5
}
coinCounter += remainder2; //number of 1cts
printf("%i\n",coinCounter);
}
Does it solve your problem with 4.2 ? I can't test right now.
The issue is that you have taken the change variable as a float, while all the other variables are ints.
The conversion of a float to an int introduces small unpredictable errors and can fail in some cases.
If you are interested in there is a very good article here.
I would suggest that you take the input as cents, or if that is not possible, take another integer variable and convert to cents at the start of the program and use that instead in the calculations.
As EOF has (rather snarkily) pointed out in their comment you are running into an issue with floating point numbers. Floating point numbers are a not perfect, there are many (infinitely many) numbers that can't be exacltly represented by a C float or double.
There's lots of good information on the web about this, for example here but the short explanation is that some decimal values when calculated in C using floats give the wrong answer and one such number is 4.2 * 100 in your particular compiler.
One possible solution in your case is to convert the float to a long, so something like:
change = change * 100 ;
long value = change >= 0 ? (long)(change+0.5) : (long)(change-0.5) ;
This should give you the exact number of cents and remove the small error in the floating calculation.
As an aside these effects can be dificult to see sometimes, try printing the result of this:
float x = 4.2 * 100 ;
float y = 4.2 ;
y = y * 100 ;
In my compiler this does result in 420 in x but 419.99... in y.
As others have pointed out, floating point values cannot always be represented perfectly. To address the error, you can round to the nearest integer. Here is a very simple function to start with:
int round(float number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}
Use it in your code like this:
int main(void)
{
float change = 0;
int changed = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
int remainder3 = 0;
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
//converts amount in dollars to cents
changed = round(change*100);//changes 419... to 420 etc.
...(more code)
You will have to experiment with corner cases to make it work well for all conditions, but this will get you started.
Note: this code example for rounding is over simplified, and provided just to get you started. The problem is really more complicated as illustrated by this conversation dealing with rounding floats to nearest integer value.
Related
I want to read digit by digit the decimals of the sqrt of 5 in C.
The square root of 5 is 2,23606797749979..., so this'd be the expected output:
2
3
6
0
6
7
9
7
7
...
I've found the following code:
#include<stdio.h>
void main()
{
int number;
float temp, sqrt;
printf("Provide the number: \n");
scanf("%d", &number);
// store the half of the given number e.g from 256 => 128
sqrt = number / 2;
temp = 0;
// Iterate until sqrt is different of temp, that is updated on the loop
while(sqrt != temp){
// initially 0, is updated with the initial value of 128
// (on second iteration = 65)
// and so on
temp = sqrt;
// Then, replace values (256 / 128 + 128 ) / 2 = 65
// (on second iteration 34.46923076923077)
// and so on
sqrt = ( number/temp + temp) / 2;
}
printf("The square root of '%d' is '%f'", number, sqrt);
}
But this approach stores the result in a float variable, and I don't want to depend on the limits of the float types, as I would like to extract like 10,000 digits, for instance. I also tried to use the native sqrt() function and casting it to string number using this method, but I faced the same issue.
What you've asked about is a very hard problem, and whether it's even possible to do "one by one" (i.e. without working space requirement that scales with how far out you want to go) depends on both the particular irrational number and the base you want it represented in. For example, in 1995 when a formula for pi was discovered that allows computing the nth binary digit in O(1) space, this was a really big deal. It was not something people expected to be possible.
If you're willing to accept O(n) space, then some cases like the one you mentioned are fairly easy. For example, if you have the first n digits of the square root of a number as a decimal string, you can simply try appending each digit 0 to 9, then squaring the string with long multiplication (same as you learned in grade school), and choosing the last one that doesn't overshoot. Of course this is very slow, but it's simple. The easy way to make it a lot faster (but still asymptotically just as bad) is using an arbitrary-precision math library in place of strings. Doing significantly better requires more advanced approaches and in general may not be possible.
As already noted, you need to change the algorithm into a digit-by-digit one (there are some examples in the Wikipedia page about the methods of computing of the square roots) and use an arbitrary precision arithmetic library to perform the calculations (for instance, GMP).
In the following snippet I implemented the before mentioned algorithm, using GMP (but not the square root function that the library provides). Instead of calculating one decimal digit at a time, this implementation uses a larger base, the greatest multiple of 10 that fits inside an unsigned long, so that it can produce 9 or 18 decimal digits at every iteration.
It also uses an adapted Newton method to find the actual "digit".
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <gmp.h>
unsigned long max_ul(unsigned long a, unsigned long b)
{
return a < b ? b : a;
}
int main(int argc, char *argv[])
{
// The GMP functions accept 'unsigned long int' values as parameters.
// The algorithm implemented here can work with bases other than 10,
// so that it can evaluate more than one decimal digit at a time.
const unsigned long base = sizeof(unsigned long) > 4
? 1000000000000000000
: 1000000000;
const unsigned long decimals_per_digit = sizeof(unsigned long) > 4 ? 18 : 9;
// Extract the number to be square rooted and the desired number of decimal
// digits from the command line arguments. Fallback to 0 in case of errors.
const unsigned long number = argc > 1 ? atoi(argv[1]) : 0;
const unsigned long n_digits = argc > 2 ? atoi(argv[2]) : 0;
// All the variables used by GMP need to be properly initialized before use.
// 'c' is basically the remainder, initially set to the original number
mpz_t c;
mpz_init_set_ui(c, number);
// At every iteration, the algorithm "move to the left" by two "digits"
// the reminder, so it multplies it by base^2.
mpz_t base_squared;
mpz_init_set_ui(base_squared, base);
mpz_mul(base_squared, base_squared, base_squared);
// 'p' stores the digits of the root found so far. The others are helper variables
mpz_t p;
mpz_init_set_ui(p, 0UL);
mpz_t y;
mpz_init(y);
mpz_t yy;
mpz_init(yy);
mpz_t dy;
mpz_init(dy);
mpz_t dx;
mpz_init(dx);
mpz_t pp;
mpz_init(pp);
// Timing, for testing porpuses
clock_t start = clock(), diff;
unsigned long x_max = number;
// Each "digit" correspond to some decimal digits
for (unsigned long i = 0,
last = (n_digits + decimals_per_digit) / decimals_per_digit + 1UL;
i < last; ++i)
{
// Find the greatest x such that: x * (2 * base * p + x) <= c
// where x is in [0, base), using a specialized Newton method
// pp = 2 * base * p
mpz_mul_ui(pp, p, 2UL * base);
unsigned long x = x_max;
for (;;)
{
// y = x * (pp + x)
mpz_add_ui(yy, pp, x);
mpz_mul_ui(y, yy, x);
// dy = y - c
mpz_sub(dy, y, c);
// If y <= c we have found the correct x
if ( mpz_sgn(dy) <= 0 )
break;
// Newton's step: dx = dy/y' where y' = 2 * x + pp
mpz_add_ui(yy, yy, x);
mpz_tdiv_q(dx, dy, yy);
// Update x even if dx == 0 (last iteration)
x -= max_ul(mpz_get_si(dx), 1);
}
x_max = base - 1;
// The actual format of the printed "digits" is up to you
if (i % 4 == 0)
{
if (i == 0)
printf("%lu.", x);
putchar('\n');
}
else
printf("%018lu", x);
// p = base * p + x
mpz_mul_ui(p, p, base);
mpz_add_ui(p, p, x);
// c = (c - y) * base^2
mpz_sub(c, c, y);
mpz_mul(c, c, base_squared);
}
diff = clock() - start;
long int msec = diff * 1000L / CLOCKS_PER_SEC;
printf("\n\nTime taken: %ld.%03ld s\n", msec / 1000, msec % 1000);
// Final cleanup
mpz_clear(c);
mpz_clear(base_squared);
mpz_clear(p);
mpz_clear(pp);
mpz_clear(dx);
mpz_clear(y);
mpz_clear(dy);
mpz_clear(yy);
}
You can see the outputted digits here.
Your title says:
How to compute the digits of an irrational number one by one?
Irrational numbers are not limited to most square roots. They also include numbers of the form log(x), exp(z), sin(y), etc. (transcendental numbers). However, there are some important factors that determine whether or how fast you can compute a given irrational number's digits one by one (that is, from left to right).
Not all irrational numbers are computable; that is, no one has found a way to approximate them to any desired length (whether by a closed form expression, a series, or otherwise).
There are many ways numbers can be expressed, such as by their binary or decimal expansions, as continued fractions, as series, etc. And there are different algorithms to compute a given number's digits depending on the representation.
Some formulas compute a given number's digits in a particular base (such as base 2), not in an arbitrary base.
For example, besides the first formula to extract the digits of π without computing the previous digits, there are other formulas of this type (known as BBP-type formulas) that extract the digits of certain irrational numbers. However, these formulas only work for a particular base, not all BBP-type formulas have a formal proof, and most importantly, not all irrational numbers have a BBP-type formula (essentially, only certain log and arctan constants do, not numbers of the form exp(x) or sqrt(x)).
On the other hand, if you can express an irrational number as a continued fraction (which all real numbers have), you can extract its digits from left to right, and in any base desired, using a specific algorithm. What is more, this algorithm works for any real number constant, including square roots, exponentials (e and exp(x)), logarithms, etc., as long as you know how to express it as a continued fraction. For an implementation see "Digits of pi and Python generators". See also Code to Generate e one Digit at a Time.
I can't understand why the code below doesn't work properly with the value 4.2. I learnt using a debugger that 4.2 isn't actually the number four point two; rather as a floating point value 4.2 becomes 4.19999981
To make up for this, I just added change = change + 0.00001; there on line 18.
Why do I have to do that? Why is this the way floating point integers work?
#include <stdio.h>
#include <cs50.h>
float change;
int coinTotal;
int main(void)
{
do {
// Prompting the user to give the change amount
printf("Enter change: ");
// Getting a float from the user
change = get_float();
}
while (change < 0);
change = change + 0.00001;
// Subtracting quarters from the change given
for (int i = 0; change >= 0.25; i++)
{
change = change - 0.25;
coinTotal++;
}
// Subtracting nickels from the remaining change
for(int i = 0; change >= 0.1; i++)
{
change = change - 0.1;
coinTotal++;
}
// Subtracting dimes from the remaining change
for(int i = 0; change >= 0.05; i++)
{
change = change - 0.05;
coinTotal++;
}
// Subtracting pennies from the remaining change
for(int i = 0; change >= 0.01; i++)
{
change = change - 0.01;
coinTotal++;
}
// Printing total coins used
printf("%i\n", coinTotal);
}
Typically float can represent about 232 different values exactly. With float, 4.2 is not one of them. Instead the value is about 4.19999981 as OP has reported.
Working with fractional money is tricky. Rarely is float an acceptable type for money. This details some alternatives like base-10 FP, double, integers and custom types.
If code stays with some FP type, change >= 0.1, and other compares, need to alter to change >= (0.01 - 0.005) or the like. The compare needs to be tolerant of values just less than or greater than a multiple of 0.01.
As you have discovered. It's impossible to represent rational numbers as floating-point values on computers, due to the fact that the machine is storing it in a somewhat fixed sized ammount of bits.
The most common standard is IEEE 754 Check here
Most commonly you will work with floats that are in single precision (32 bits in total). The number is represented as 1 bit for sign, 8 bits for exponent , 23 bits for mantissa.
The representation is as follows x=S*M*B^E where:
S - sign (-1 or 1)
M - mantissa (a normalized fraction)
B - Base (here as 2)
E - exponent ( 8bits -> -128,127 or 0,255 depending on definition in standard)
This fraction is (M) causing the problems with accurate representation of values. You need to represent a certain aproximation while being given a limited ammount of bits (You can only accurately represent values that can be combined by summing 1/2, 1/4, 1/8... )
Commonly 32 bits allows you for precision for around 6 places in fraction.
You can use 64 bit (double) for a greater range and slightly better precision.
Make every number in your program 100 times bigger, use the math.h roundf function, and divide the result by 100 when you are about to print the value to the screen.
I have an array of integer element range up to 10^5, and I have to find the first element after the total multiplication.
Example:
Array : 2,4,6,7
multiplication result: 336 and the first element is 3.
Obviously I cannot multiply the elements with the range up to 10^5.
How can I track only the first digit during multiplication?
We can also find the first digit with another method.
Suppose p be the final value after multiplying all the elements.
So, we have to find
P = a[0]*a[1]*a[2]*a[3]*.......*a[n-1]
for n sized array then we can take log with base 10 on both the side after that our expression changes to
log(p) = log(a[i])+log(a[1])+log(a[2])+.....+log(a[n-1])
Now, to find the first digit we have to get the fractional part of this variable sum which can be done in this way
frac = sum - (integer)sum
and at the last step calculate the 10^frac and convert it to the integer value which is our required first digit.
This algorithm is better in comparison to time complexity.
int getFirstDigit(long a[], long n) {
double p;
for(int i=0;i<n;i++) {
p = p+log10(a[i]);
}
double frac = p - (long)p;
int firdig = (int)pow(10,frac);
return firdig;
}
In c or c++ make integer data type as long double such that first digit of number is before decimal point and rest are after decimal point.
Above can be done as follows:-
long double GetFraction(int number){
int length = (int) log(number) + 1; // this will give number of digits in given number. And log is log base 10.
long double fraction = (long double) number / (10^(length - 1);
return fraction;
}
Example :-
Let number = 12345
length = log(12345) + 1 = 5;
fraction = (long double) 12345 / (10^4) = 1.2345
Now for all integers in array find fraction as mention above and multiply them as follow:-
int GetFirstDigit(int arr[] , int size){
if(size == 0)
return 0;
long double firstDigit = 1.0;
for(int i = 0 ; i < size ; i++){
firstDigit = firstDigit*GetFraction(arr[i]);
if(firstDigit >= 10.00) // You have to shorten your number otherwise it will same as large multiplication and will overflow.
firstDigit/=10;
}
return (int) firstDigit;
}
Disclaimer:- This is my approach and I don't have any formal proof about accuracy of result. But I have verified result for integer up to 10^9 and array size up to 10^5
Please donot forget to note that this is just an attempt to make you understand the logic and that you need to make changes in the code as per your requirement. I strongly suggest you make this a subroutine in your program and parse the arguments to it from the main thread in your program.
#include <stdio.h>
void main()
{
int num1, num2;
printf("Enter ur lovely number:\n");
scanf("%d",&num1);
num2=num1;
while(num2)
{
num2=num2/10;
if(num2!=0)
num1=num2;
}
printf("The first digit of the lovely number is %d !! :P\n ",num1);
}
Try this approach,
Take integer as input let us say int x1, now copy this in a double let us say double x2, and suppose you have previous product as double y, initially y = 1 . now use this loop,
while(x1!<10){
x1 = x1/10;
x2 = x2/10; //this will make double in standard form x*10^y without 10^y part
}
ex x1 = 52, then x2 will be converted to 5.2.
Now let us assume y = 3 and x is 5.2.
then product now is 15.6, again reduce this to 1.56 and repeat the process. in the end you will have the only digit before the decimal as the first digit of the product of all the numbers.
#include <cs50.h>
#include <stdio.h>
int main(void) {
printf("Enter your change: ");
int pennies = 0, nickels = 0, dimes = 0, quarters = 0;
float change = GetFloat();
while (change > 0) {
if (change >= 0.25) {
quarters++;
change -= 0.25;
}
else if (change >= 0.10) {
dimes++;
change -= 0.10;
}
else if (change >= 0.05) {
nickels++;
change -= 0.05;
}
else if (change >=0.01) {
pennies++;
change -= 0.01;
}
// force break
else {
printf("%1.2f - Num. of change left\n", change);
break;
}
}
printf("Quarters: %d\n", quarters);
printf("Dimes: %d\n", dimes);
printf("Nickels: %d\n", nickels);
printf("Pennies: %d\n", pennies);
return 0;
}
Hello, I'm currently new to C and I'm taking Harvard's CS50 class online. The "change" variable seems to go down to 0.00 without stopping the while-loop. This forced me to type in "break" at the end. What is wrong with my code?
This is from problem set 1 by the way.
There are problems with how floating point numbers are represented in a computer memory. If in short: not all numbers can be stored precisely. Please read this page for more details: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
You can use this service to check the representations of floats in a computer: http://www.binaryconvert.com/result_float.html
Regarding your case, let's assume you have entered 0.4. That means it should be divided into 0.25 + 0.1 + 0.05. And change is supposed to be zero, but:
0.40 == 0.4000000059604644775390625000,
minus
0.25 == 0.2500000000000000000000000000 (exact),
minus
0.10 == 0.1000000014901161193847656250,
minus
0.05 == 0.0500000007450580596923828125
is
0.00 == 0.0000000037252902984619140625
As you can see, the final result is slightly above zero, what prevents your loop from ending.
Generally, if you need to count money, you should use int instead to count "cents". Or custom types. Or long arithmetic. Or whatever, but not floating points, because money in most countries needs only two positions after a point, thus this point needs not to be floating.
You should not use floating point numbers for representing numbers that are integral by nature. Floating point arithmetic is a problem here. Change in most cases will never be equal to 0. You should just do everything with integers and it will work. Algorithm looks fine.
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
http://floating-point-gui.de/
As others have said, this is a floating point issue. Here's your problem:
else if (change >=0.01) {
pennies++;
change -= 0.01;
}
What's probably happening is that change ends up very slightly higher than 0.01, so when you subtract 0.01 from it, it ends up being slightly greater than zero, but less than 0.01, and you have no if clauses to deal with that eventuality, so it goes on forever. Your printf() shows zero because you're rounding it down to two decimal places, so it looks like 0.00 even though it's probably 0.00001 or something.
it isn't wise to use floats for this, as stated a several times here...
but logically you can do what you are trying, and I suspect it has to do with comparison and promotion rules in C... but I would guess this will fix your problem:
while (change > 0.0f)
that way you are comparing like types...
really you should change to using int, long, or long long... and representing cents rather than dollars.
Untested, but here's how I'd have written it. It uses int rather than float to avoid rounding problems, has a table-driven computation for each of the coins, and does division rather than repeated subtraction.
int change = GetFloat() * 100 + 0.5;
struct {const char *name; int value;} coins[] = {
{"Quarters", 25},
{"Dimes", 10},
{"Nickels", 5},
{"Pennies", 1},
};
for (int i = 0; i < 4; i++) {
int coin = change / coins[i].value;
change %= coins[i].value;
printf("%s: %d\n", coins[i].name, coin);
}
You should use the integer equivalent of getFloat(), or use an integer variable to do the comparisions. The code is going wrong because of floating point issues.
#include<math.h> // for round
...
...
int change = int)100 * round(getFloat());
I was trying to solve a problem using C on project euler click here
Here is the code. It works fine for 10 values but for 1000 values it gives a wrong output. I noticed that it gives a right output till 32. I think I'm exceeding the memory or something. How do I allocate memory for such a large array?
#include <stdio.h>
int main() {
int a[10], i, sum=1, b=0;
for(i = 1; i < 10; i++) {
a[0] = 1;
a[i] = sum + a[i-1];
sum = sum + a[i-1];
}
for(int j = 1;j > 0; j++) {
b = b + sum%10;
if(sum<10)
break;
sum = sum/10;
}
printf("%d\n",b);
return 0;
}
You might try computing 21000 as an 80-bit long double, then using sprintf to convert it to a string, then summing the digits of that string.
Why this works:
Floating-point types store numbers as a mantissa times an exponent. The exponent is always a power of two, and the mantissa can be 1. For a long double, the exponent can be up to 216383. printf and friends, on modern implementations, will correctly print out the digits of a floating-point number.
Code:
int main() {
char buf[1024]; int ans = 0;
sprintf(buf, "%.0f", 0x1.0p1000);
for (int i = 0; buf[i]; i++) ans += buf[i] - '0';
printf("%i\n", ans);
}
I noticed that it gives a right output till 32
That is, because the integer type you're using has 32 bits. It simply can't hold larger numbers. You can't solve it the conventional way.
Here's what I'd suggest: First let's estimate how many digits that number will have. Every time a number gets 10-fold in decimal writing a new digit is required. So the number of digits for a number in decimal is given by ceil(log10(n)). So for 2^1000 you need ceil(log10(2^1000)) digits, but that is just ceil(1000*log10(2)) = 302, so you'll need 302 decimal digits to write it down.
This gives the next idea: Write down the number 1 in 302 digits, i.e. 301 times '0' and one '1' in a string. Then double the string 1000 times, by adding it to itself just like in elementary school, carrying the overflowing digits.
EDIT I think I should point out, that the problem encountered is the whole point of this Project Euler problem. Project Euler problems all have in common, that you can not solve them by using naive programming methods. You must get creative to solve them!