I was reading through an amusing article that I found while browsing my Twitter feed and stumbled upon a simple problem, and that is to programmatically (and efficiently) find two numbers whose product (multiplication) equals 119. The author states that we cannot use 1, or 119, and which means that we are dealing with a non-deterministic polynomial problem ("easy to verify, but hard to solve").
Well, why can't we make the solve part easy too?
Now, the author's explanation of the problem may not have been sufficient, as I know nothing about the P vs. NP problem, but I did instantly recognize something while reading it; it's actually a simply problem to tackle, if you know where to look!
The author then goes on to say "you probably have to go through all possible numbers from 2 to 118". <--- That line was the breaking point for my concentration. I thought that "there's no way you have to go through that many iterations for this application. That's absurd!" I instantly grabbed a pen and some paper and after a few minutes I was already typing out the C source code in a Vim which defies that. The way I did it was to take the tiny sequential steps and drop a lot of them and then make the remaining steps taller (so-to-speak).
Well if the number is not divisible by those, we increment each by 10 (becoming 13, 17, and 19) and try again. We repeat this ONLY until we get halfway up the stair case. Yeah, that's right, I just dropped even more sequential steps (half of them) from the solution the author provided. Why I do this may be obvious. If we look at numbers that are divisible by other numbers, they are never divisible by numbers higher than half of their own value. For instance 1336 is divisible by 2 which equals 668. It has no factor larger than that. Same goes for 10. 10 is divisible by 1,2, and 5, but nothing above five.
The first function outside of
This returns the value to the user and exits instantly. That means that we can instantly calculate any integer value whose least significant (ones place) value is 0,2,4,5,6 and 8. No (mathematical) verification needs done at all. That only leaves us with 1,3,7, and 9. So how many values are there that end with these four numbers "from 2 to 118" in the context of the article author's example? Well, 46 to be exact. I know this because I modified the code to output the number when sent into the
Well, I begin with three simple calculations, for modulo,
Yeah, those damned things. Well, I compensated for that by letting the application go off into a
~Douglas
Well, why can't we make the solve part easy too?
Now, the author's explanation of the problem may not have been sufficient, as I know nothing about the P vs. NP problem, but I did instantly recognize something while reading it; it's actually a simply problem to tackle, if you know where to look!
The author then goes on to say "you probably have to go through all possible numbers from 2 to 118". <--- That line was the breaking point for my concentration. I thought that "there's no way you have to go through that many iterations for this application. That's absurd!" I instantly grabbed a pen and some paper and after a few minutes I was already typing out the C source code in a Vim which defies that. The way I did it was to take the tiny sequential steps and drop a lot of them and then make the remaining steps taller (so-to-speak).
Dyslexia
We read our text here in the the US, from left to right. We read our numbers from right to left! Yeah, that's right, we evaluate the columns starting with the least significant column, (the ones column for integers)! Anyways, the least significant column is the one which holds the most clues about a number, obviously. For instance, numbers that end in 2, 4, 6, 8 are all divisible by two. Well, if the number given in the article was 118, we could have instantly said 2 * 29 and been done with it, since that's neither 1 nor 118. Also, if the least significant column is a 5 or 0, assuming there is a tens column value for the latter, they are both divisible by 5. Well, that leaves us with 1,3,7, and 9. But wait a minute, the author says we cannot use 1. So now we are down to 3, 7, and 9!Well if the number is not divisible by those, we increment each by 10 (becoming 13, 17, and 19) and try again. We repeat this ONLY until we get halfway up the stair case. Yeah, that's right, I just dropped even more sequential steps (half of them) from the solution the author provided. Why I do this may be obvious. If we look at numbers that are divisible by other numbers, they are never divisible by numbers higher than half of their own value. For instance 1336 is divisible by 2 which equals 668. It has no factor larger than that. Same goes for 10. 10 is divisible by 1,2, and 5, but nothing above five.
C Programming
So, how does this translate into an algorithm and source code? Well, I did it in C programming, but added a massive amount of comments on the way through the code. I also broke the source code up into functions without any global variables so that I could easily explain what each does here in this weblog.The first function outside of
main()
is void checkType(char *ct);
This function simply deduces what kind of mathematics will be used on the entire number. It gathers this information by simply using the least significant value, or value in the ones column. I use the modulo function in C after converting the input as an integer. This gathers the last digit into the integer symbol, ictm
, named for "integer check type modulo". If ictm
equals 5 or 0, or 2,4,6, or 8, we process it with the function void processEasy(int ict,int even);
This returns the value to the user and exits instantly. That means that we can instantly calculate any integer value whose least significant (ones place) value is 0,2,4,5,6 and 8. No (mathematical) verification needs done at all. That only leaves us with 1,3,7, and 9. So how many values are there that end with these four numbers "from 2 to 118" in the context of the article author's example? Well, 46 to be exact. I know this because I modified the code to output the number when sent into the
void processHard(int ict)
function that I made. This function is for handling odd (least significant) numbers that aren't 1,5, or 0. That's 46 out of 117. That means that I only have to mathematically verify about 39% of the numbers. That's not too shabby. Well, I begin with three simple calculations, for modulo,
if(ict%3==0)
, if(ict%7==0)
, and finally if(ict%9==0)
. Well, guess what? The second calculation got his number, 119! That means I only performed 2 verification calculations for this sum! That's about 1.7% of his "from 2 to 118" method! Bingo? No bingo. No why? Because prime numbers, that's why. Yeah, those damned things. Well, I compensated for that by letting the application go off into a
while()
loop into the void processInsane(int ict);
function. This function is pretty cool because it performs a simple stack-oriented (pemdas-like) POSTFIX inline with the modulo function in C. There were 26 prime numbers between 2 and 118. That's only 26 calls to the heavy-lifting void processInsane(int ict);
subroutine. 26 is 21% of 119. Not too shabby? That's just over one-fifth of the "verification" required for numbers 2-118. ~Douglas