CS50 Week 1, Credit - If comparison issue? Int size limit? - c

I'm new to CS50 and C and I'm currently working on the Week 1 assignment 'Credit'. I've got most of it working, but I'm running into an issue where no matter how true I feel a statement should be, my if comparison is flagging it false. Is my logic off, or am I missing something? Is there a limit on the size of a number I can use in If comparisons?
Here's my code so far:
#include <cs50.h>
#include <stdio.h>
unsigned char cardArray[20];
unsigned long creditCard;
string cardType; //String used for checking what type of credit card has been submitted.
//int remainder;
int n = 0;//Increment array position
int x = 0;
int main(void)
{
creditCard = get_long("Input: "); //Prompt user for CC
printf("%lu", creditCard);
while(creditCard > 0 && creditCard != 0) //Take CC Int and convert to Char Array for math functions
{
cardArray[n] = (creditCard % 10); //Modulus creditCard remainder
//printf("%i\n", n); //Array indices check
creditCard = (creditCard / 10); //Reduce creditCard by factor of 10
printf("%d\n", cardArray[n]);
n += 1; //increment Array indices
}
printf("Pos 15: %d\n", cardArray[15]);
//Use if >= to check size of creditCard
if(creditCard > 1000000000000 && creditCard <= 9999999999999){printf("X3: %s\n", cardType); //Check for creditCard length of 13
if(cardArray[12] == 4){
cardType = "VISA\n";
}
}else printf("X: %s\n", cardType);
if(creditCard >= 100000000000000 && creditCard <= 999999999999999){ printf("X1: %s\n", cardType);//Check for creditCard length of 15
if(cardArray[14] == 3 && (cardArray[13] == 4 || cardArray[13] == 7)){//If 15 AND starts with 34 OR 37 then set card value to American Express
cardType = "AMEX\n";
}
}else printf("X: %s\n", cardType);
if(creditCard >= 1000000000000000 && creditCard <= 9999999999999999){printf("X2: %s\n", cardType); //Check for creditCard length of 16
if(cardArray[15] == cardArray[15]){//Does it start with 4? set card value to Visa
cardType = "VISA\n";
printf("%s", cardType);
}
else printf("X: %s\n", cardType);
if(cardArray[15] == 5 && (cardArray[14] == 1 || cardArray[14] == 2 || cardArray[14] == 3 || cardArray[14] == 4 || cardArray[14] == 5)){//Does it begin with 51, 52, 53, 54, or 55? set card value to Master Card
cardType = "MASTERCARD\n";
}
}
else cardType = "INVALID\n";
printf("%s", cardType);
}
I've tested with several printf lines to see where my code is going. If I change comparisons to something like 1 == 1 I can flag the comparison as true, but using comparisons like creditCard >= 1000000000000 will always fail, even if I'm passing along 10000000000000.

An unsigned long on your target is likely a 32 bit value. 232 = 4294967296, so clearly the comparison with 10000000000000 for example will always evaluate to false.
If your compiler did not issue any warnings, you should look at your compiler settings.
Change the type of creditCard to unsigned long long or better uint64_t (declared in <stdint.h>). Then you should also specify the the literal integer with the ULL suffix, eg:
creditCard >= 100000000000000ULL
However, the implementation is seriously flawed. You get the card number as an integer then convert it to a string. Since your data type will not hold a credit card number, both the string and the integer will be incorrect. Credit card numbers are not arithmetic objects, and storing as an integer is a bad idea for more reasons that just range - even a uint64_t is only good for 19 digits - which may be enough for now, but possibly not in future. The number should be received and processed as a string. The advantages are that you can perform more sophisticated validation, allow digit grouping spaces, and will not loose leading zero digits.
String comparisons on normalised digit strings (i.e. with spaces removed) will work as well as an arithmetic comparison. For example:
if( strcmp( cardNumberString, "10000000000" ) >= 0 )
achieves the same result as:
if( cardNumberUnsLongLong >= 10000000000ULL )

Related

Printing a copy of a given 4 digit number but every prime digit is followed by the number which is one greater than it

So I've been trying to create a program which asks the user for a 4 digit number, and prints it's copy but every prime digit is just followed by a number just greater than it. (Eg. 2345 becomes 2334456)
So what I tried was first finding storing all the digits and then printing them out as strings, followed by the next number if any of them were prime using if statements. Now this seems to give a different output than I'd expect. 2345 gives 23235656 for example. Where did I go wrong?
#include <stdio.h>
int main() {
unsigned int userinput;
unsigned int onesplace;
unsigned int tensplace;
unsigned int hundredsplace;
unsigned int thousandsplace;
printf("Please print your number /n");
scanf("%u", &userinput);
onesplace = userinput%10;
tensplace = ((userinput-onesplace/10))%10;
hundredsplace = ((userinput - onesplace -10*tensplace)/100)%10;
thousandsplace = ((userinput - onesplace - 10*tensplace - 100*hundredsplace)/1000);
printf("%u", thousandsplace);
if ((thousandsplace == 2)||(thousandsplace == 3)||(thousandsplace == 5)||(thousandsplace == 7)) {
unsigned int newnum = thousandsplace + 1;
printf("%u", newnum);
}
printf("%u", hundredsplace);
if ((hundredsplace == 2)||(hundredsplace == 3)||(hundredsplace == 5)||(hundredsplace == 7)) {
unsigned int newnum2 = hundredsplace + 1;
printf("%u", newnum2);
}
printf("%u", tensplace);
if ((tensplace == 2)||(tensplace == 3)||(tensplace == 5)||(tensplace == 7)) {
unsigned int newnum3 = tensplace + 1;
printf("%u", newnum3);
}
printf("%u", onesplace);
if ((onesplace == 2)||(onesplace == 3)||(onesplace == 5)||(onesplace == 7)) {
unsigned int newnum4 = onesplace + 1;
printf("%u", newnum4);
}
}
You are miscalculating the tensplace, essentially forgetting to divide the tens value by 10.
Change (userinput-onesplace/10) to (userinput/10).
Then with an input of 2345 you get output
Please print your number /n2334456
The probably unwanted "/n", visible here in the single output line because I used https://www.tutorialspoint.com/compile_c_online.php (with is non-interactively provided standard input), is a separate unrelated problem.

C variable specified as a long long but recognized as an int

I'm working on a program that checks the validity of credit card numbers for the CS50 class I'm taking (it's legal I swear haha) and I'm currently working on correctly getting the first two numbers of each CC# to check what company it is from. I've commented what each part does for clarity and also commented where my problem arises.
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <math.h>
#include <string.h>
int main(void)
{
long long ccn = get_long_long("Enter CCN: \n");
int count = 0;
long long ccn1 = ccn;
// finds the amount of digits entered and stores that in int count.
while (ccn1 != 0)
{
ccn1 /= 10;
+count;
}
printf("%i \n", count);
// ln 17- 19 should take int count, subtract two, put that # as the power of 10,
// then divide the CC# by that number to get the first two numbers of the CC#.
long long power = count - 2;
// here is where i get the error. its a long long so it
// should hold up to 19 digits and im only storing 14 max
// but it says that 10^14th is too large for type 'int'
long long divide = pow(10,power);
long long ft = ccn / divide;
printf("power: %i \n", power); //ln 20-22 prints the above ints for debug
printf("Divide: %lli \n", divide);
printf("First two: %lli \n", ft);
string CCC;
// ln 24-35 cross references the amount of digits in the CC#
// and the first two digits to find the comapany of the credit card
if ((count == 15) && (ft = 34|37))
{
CCC = "American Express";
}
else if ((count == 16) && (ft = 51|52|53|54|55))
{
CCC = "MasterCard";
}
else if ((count = 13|16) && (ft <=49 && ft >= 40))
{
CCC = "Visa";
}
printf("Company: %s\n", CCC);
}
The first issue is the +count in the loop. This should be ++count. Because of this, count stays at 0 and power = -2. You can avoid all that power stuff. You already have the loop, you can use it to get the first two digits:
int ft = 0;
while (ccn1 != 0)
{
// When you are down to 10 <= ccn1 < 100, store it
if (ccn1 < 100 && ccn1 > 9) ft = ccn1;
ccn1 /= 10;
++count;
}
Your second issue is how you do your comparisons.
if ((count == 15) && (ft = 34|37))
First, = is assignment, and == tests equality. Second, | is bitwise OR, || is logical OR. Third, you can't test multiple values like that. Correct way:
if ((count == 15) && (ft == 34 || ft == 37))

Convert index to sequence from custom alphabet

I would like to produce a function which takes an integer x and char array in, and returns a string x steps into the sequence.
For example, consider the alphabet 'abc', which would produce the strings a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab... If the index 0 was passed in, I would expect the output to be 'a'; likewise, if the index 34 was passed in, I would expect the output 'cbb'.
For the alphabet '0123456789' I would expect the strings 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11...
I have written the following thus far, but am getting stuck on cases 21-23, 33-35, 45-47 where the behaviour deviates and I've been staring at this for a number of hours now without a pattern jumping out at me (with respect to the alphabet size and index). At first I didn't notice the issue, using a larger sized alphabet until it created bigger issues further in my program.
I'm not going to pretend the code below is in anyway elegant, following good practice, nor optimised - at this stage I really just want to understand the correct implementation of this pattern and have been changing things all over the place to attempt to resolve the issue. Apologies in advance if the variable names are confusing. Also, is this a common pattern/issue? I have tried to search for similar algorithms but have been unable to find anything with the terms that come to mind.
unsigned long power(int num, int exp)
{
int i;
unsigned long ret = num;
if (exp == 0) return 1;
for (i = 1; i < exp; i++)
{
ret *= num;
}
return ret;
}
unsigned long sumsqr(int base, int exp)
{
unsigned long sum;
for (sum = 0; exp > 0; exp--)
{
sum += power(base, exp);
}
return sum;
}
char * generateStringT(unsigned long index, char * charmap)
{
unsigned long scaler;
unsigned long remainder;
unsigned long divisor;
int base;
int exponent;
int factor;
char * buffer;
char * string;
int i;
buffer = malloc(sizeof(char) * 100);
i = 0;
base = strlen(charmap);
exponent = 0;
divisor = 0;
remainder = index;
while(sumsqr(base, exponent) <= index)
{
exponent++;
}
exponent--;
factor = exponent;
while(factor >= 0)
{
divisor = power(base, factor);
if ((factor > 1) && (exponent > 0))
divisor += power(base, factor-1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
if ((factor == exponent) && (exponent > 0)) scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
buffer[i++] = '\0';
string = malloc((strlen(buffer) + 1) * sizeof(char));
strcpy(string, buffer);
free(buffer);
return string;
}
What you are trying to do there looks like a base conversion, but actually is slightly different. Any number in any base can be thought as if they have infinitely many preceding zeros (or whatever the least significant digit is at that base) behind the represented number. This is not true in your case.
In your case, you lay importance to the amount of digits on the number you represent, making it slightly more complicated to index them. With bases in maths, it is easy to calculate the index of a represented number in any base b; that is, sum of the rank times the base raised to the power of order for each digit. In your case, the index builds up an additional sum_{k = 1}^{amount.of.digits.on.our.number - 1} base^k. If we subtract that addition from the index, our task becomes rather easy.
That addition can be calculated using your sumsqr function.
Here, I have changed your code just a little, with comments at where I've done changes, which is able to resolve many, just like you expect it to:
// added this
remainder -= sumsqr(base, exponent);
while (factor >= 0)
{
divisor = power(base, factor);
// commented this out
// if ((factor > 1) && (exponent > 0))
// divisor += power(base, factor - 1);
scaler = remainder/divisor;
remainder = remainder - scaler * divisor;
printf("%lu,", scaler);
// commented this out
// if ((factor == exponent) && (exponent > 0))
// scaler--;
buffer[i++] = charmap[scaler];
factor--;
}
I am not exactly sure what you were trying to do with the parts I've commented out. My guess is that you were trying to increase the divisor by that amount of difference I've talked previously, instead of decreasing the index or remainder by that amount.
Hope this helps in any way.
Not a fix (at a glance, your code uses a similar idea -- but more complicated!), but this is the code I used to convert an integer index to an a,b,c-format page number:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *number_alpha (char *dest, int value, char *base)
{
char *ddest = dest, *startdest = dest, swop;
if (value < 0)
{
value = -value;
*dest = '-';
startdest++;
ddest++;
}
value++;
do
{
*ddest = base[((value-1) % strlen(base))];
ddest++;
value = (value-1)/strlen(base);
} while (value > 0);
*ddest = 0;
ddest--;
while (ddest > startdest)
{
swop = *ddest;
*ddest = *startdest;
*startdest = swop;
startdest++;
ddest--;
}
return dest;
}
int main (int argc, char **argv)
{
int number;
char result[256];
if (argc != 3)
{
printf ("usage: [number] [string]\n");
return -1;
}
number = strtol (argv[1], NULL, 10);
number_alpha (result, number, argv[2]);
printf ("%d in 'base' %s yields %s\n", number, argv[2], result);
return 0;
}
It is very similar to the common task 'convert an integer to decimal notation'. By removing the value++ and changing (value-1) twice to just value in number_alpha, you get a bog-standard Int-To-Ascii routine. This one is special because the "wrap" occurs at a different place: for a base of 0123456789, incrementing 9 shows 00, not 10.
Sample outputs:
0 in 'base' abc yields a
34 in 'base' abc yields cbb
34 in 'base' 0123456789 yields 24
-34 in 'base' abc yields -cbb
9 in 'base' 0123456789 yields 9
10 in 'base' 0123456789 yields 00
--
See Translate a column index into an Excel Column Name for a couple of implementations in other languages. They seem to focus on recursive solutions, where mine is linear (for better or worse).

Prime number in C

int prime(unsigned long long n){
unsigned val=1, divisor=7;
if(n==2 || n==3) return 1; //n=2, n=3 (special cases).
if(n<2 || !(n%2 && n%3)) return 0; //if(n<2 || n%2==0 || n%3==0) return 0;
for(; divisor<=n/divisor; val++, divisor=6*val+1) //all primes take the form 6*k(+ or -)1, k[1, n).
if(!(n%divisor && n%(divisor-2))) return 0; //if(n%divisor==0 || n%(divisor-2)==0) return 0;
return 1;
}
The code above is something a friend wrote up for getting a prime number. It seems to be using some sort of sieving, but I'm not sure how it exactly works. The code below is my less awesome version. I would use sqrt for my loop, but I saw him doing something else (probably sieving related) and so I didn't bother.
int prime( unsigned long long n ){
unsigned i=5;
if(n < 4 && n > 0)
return 1;
if(n<=0 || !(n%2 || n%3))
return 0;
for(;i<n; i+=2)
if(!(n%i)) return 0;
return 1;
}
My question is: what exactly is he doing?
Your friend's code is making use of the fact that for N > 3, all prime numbers take the form (6×M±1) for M = 1, 2, ... (so for M = 1, the prime candidates are N = 5 and N = 7, and both those are primes). Also, all prime pairs are like 5 and 7. This only checks 2 out of every 3 odd numbers, whereas your solution checks 3 out of 3 odd numbers.
Your friend's code is using division to achieve something akin to the square root. That is, the condition divisor <= n / divisor is more or less equivalent to, but slower and safer from overflow than, divisor * divisor <= n. It might be better to use unsigned long long max = sqrt(n); outside the loop. This reduces the amount of checking considerably compared with your proposed solution which searches through many more possible values. The square root check relies on the fact that if N is composite, then for a given pair of factors F and G (such that F×G = N), one of them will be less than or equal to the square root of N and the other will be greater than or equal to the square root of N.
As Michael Burr points out, the friend's prime function identifies 25 (5×5) and 35 (5×7) as prime, and generates 177 numbers under 1000 as prime whereas, I believe, there are just 168 primes in that range. Other misidentified composites are 121 (11×11), 143 (13×11), 289 (17×17), 323 (17×19), 841 (29×29), 899 (29×31).
Test code:
#include <stdio.h>
int main(void)
{
unsigned long long c;
if (prime(2ULL))
printf("2\n");
if (prime(3ULL))
printf("3\n");
for (c = 5; c < 1000; c += 2)
if (prime(c))
printf("%llu\n", c);
return 0;
}
Fixed code.
The trouble with the original code is that it stops checking too soon because divisor is set to the larger, rather than the smaller, of the two numbers to be checked.
static int prime(unsigned long long n)
{
unsigned long long val = 1;
unsigned long long divisor = 5;
if (n == 2 || n == 3)
return 1;
if (n < 2 || n%2 == 0 || n%3 == 0)
return 0;
for ( ; divisor<=n/divisor; val++, divisor=6*val-1)
{
if (n%divisor == 0 || n%(divisor+2) == 0)
return 0;
}
return 1;
}
Note that the revision is simpler to understand because it doesn't need to explain the shorthand negated conditions in tail comments. Note also the +2 instead of -2 in the body of the loop.
He's checking for the basis 6k+1/6k-1 as all primes can be expressed in that form (and all integers can be expressed in the form of 6k+n where -1 <= n <= 4). So yes it is a form of sieving.. but not in the strict sense.
For more:
http://en.wikipedia.org/wiki/Primality_test
In case the 6k+-1 portion is confusing, note that you can perform some factorization of most forms of 6k+n and some are obviously composite and some need to be tested.
Consider numbers:
6k + 0 -> composite
6k + 1 -> not obviously composite
6k + 2 -> 2(3k+1) --> composite
6k + 3 -> 3(2k+1) --> composite
6k + 4 -> 2(3k+2) --> composite
6k + 5 -> not obviously composite
I've not seen this little trick before, so it's neat, but of limited utility since a sieve of Eratosthenese is more efficient for finding many small prime numbers, and larger prime numbers benefit from faster, more intelligent, tests.
#include<stdio.h>
int main()
{
int i,j;
printf("enter the value :");
scanf("%d",&i);
for (j=2;j<i;j++)
{
if (i%2==0 || i%j==0)
{
printf("%d is not a prime number",i);
return 0;
}
else
{
if (j==i-1)
{
printf("%d is a prime number",i);
}
else
{
continue;
}
}
}
}
#include<stdio.h>
int main()
{
int n, i = 3, count, c;
printf("Enter the number of prime numbers required\n");
scanf("%d",&n);
if ( n >= 1 )
{
printf("First %d prime numbers are :\n",n);
printf("2\n");
}
for ( count = 2 ; count <= n ; )
{
for ( c = 2 ; c <= i - 1 ; c++ )
{
if ( i%c == 0 )
break;
}
if ( c == i )
{
printf("%d\n",i);
count++;
}
i++;
}
return 0;
}

Find the largest prime number factor?

I need to find
The prime factors of 13195 are 5, 7, 13 and 29.
/ * Largest is 377. * /
What is the largest prime factor of the number 600851475143 ?
#include<stdio.h>
int main()
{
int i, j = 0;
/*Code works really fine for 13195 or 26*/
long value, large = 600851475143 /*13195*/;
for(value = (large - 1) ; value >= 3; value--)
{
if(large % value == 0)
{
/*printf("I am here \n");*/
if((value % 2 != 0) && (value % 3 != 0) && (value % 5 != 0) && (value % 7 != 0) )
{
j = 1;
break;
}
}
}
if (j == 1)
{
printf("%ld", value);
}
return 0;
}
Where it is going wrong?
600851475143 is too big to fit in 32 bit integer. long may be 32 bit on your machine. You need to use 64 bit type. The exact data type will be dependent on your platform, compiler.
Your prime checking code is wrong. You are assuming that if something is not devided by 2, 3, 5, 7 then that is prime.
The most important thing that is wrong here is that your code is too slow: even if you fix other issues, such as using a wrong data type for your integers and trying out some divisors that are definitely not prime, iterating by one down from 10^11 will simply not finish in your computer's lifetime is extremely wasteful.
I highly recommend that you read through the example on page 35 of this classic book, where Dijkstra takes you through the process of writing a program printing the first 1000 prime numbers. This example should provide enough mathematical intuition to you to speed up your own calculations, including the part where you start your search from the square root of the number that you are trying to factor.
600851475143 is probably above the precision of your platform's long data type. It requires at least 40 bits to store. You can use this to figure out how many bits you have:
#include <limits.h>
printf("my compiler uses %u bits for the long data type\n", (unsigned int) (CHAR_BIT * sizeof (long)));
#include<stdio.h>
//Euler problem #3
int main(){
long long i, sqi;
long long value, large = 600851475143LL;
long long max = 0LL;
i = 2LL;
sqi = 4LL; //i*i
for(value = large; sqi <= value ; sqi += 2LL * i++ + 1LL){
while(value % i == 0LL){
value /= (max=i);
}
}
if(value != 1LL && value != large){
max = value;
}
if(max == 0LL){
max = large;
}
printf("%lld\n", max);
return 0;
}
You need to add an L as suffix to a number that overflow MAX INT, so this line:
long value, large = 600851475143;
Should be:
long value, large = 600851475143L;
// ^
In order to do this you need to establish that the value is prime - i.e. that is has no prime factors.
Now your little piece of code checking 3/5/7 simply isn't good enough - you need to check is value has ANY lower prime factors (for example 11/13/17).
From a strategic perspective if you want to use this analysis you need to check a list of every prime factor you have found so far and check against them as you are checking against the first 3 primes.
An easier (but less efficient) method would be to write an IsPrimeFunction() and check the primality of the each divisor and store the largest.
public class LargeFactor{
public static void main(String []args){
long num = 600851475143L;
long largestFact = 0;
long[] factors = new long[2];
for (long i = 2; i * i < num; i++) {
if (num % i == 0) { // It is a divisor
factors[0] = i;
factors[1] = num / i;
for (int k = 0; k < 2; k++) {
boolean isPrime = true;
for (long j = 2; j * j < factors[k]; j++) {
if (factors[k] % j == 0) {
isPrime = false;
break;
}
}
if (isPrime && factors[k] > largestFact) {
largestFact = factors[k];
}
}
}
}
System.out.println(largestFact);
}
}
Above code utilises the fact that we only need to check all numbers up to the square root when looking for factors.

Resources