|
|
#1 |
|
C: Arbitrary-precision can't correctly subtract
I finally got a basic Arbitrary-precision system up and running only on addition. I'm now doing one in subtract and the problem is that when doing the "subtracting one from the top number next to you on the left and adding ten to the top digit that is below in value of the bottom digit"(I honestly can't describe it very well, but I think you can interoperate that), it doesn't change the digit that was borrowed from even though I'm using pointers. It does, however, properly add ten if the top digit is too small.
I posted my code for subtraction: Code:
void subtractNumbers(int space,int number[], int number2[], int *toStore)
{
int goUp=0;
int *p;
int *q;
int *r;
r=toStore;
for(int digit = (space-1); digit >= 0; digit--)
{
p = &number[digit]; //Grabs the digit
q = &number2[digit]; //Grabs the digit
while(*p < *q) //If the bottom digit is higher than the top digit
{
goUp++; //Checks one digit ahead
p = &number[digit+goUp]; //Goes to the next digit
if(*p!=0) //If the next digit isn't a zero
{
*p-=1; //It'll then subtract one
while(goUp>0) //While there are possibly more digits
{
goUp--; //We'll go down one digit
p = &number[digit+goUp];
if((*p==0) && (goUp > 0)) //If the digit is zero and there are more than one digit to carry over
{
*p=9;
}
if(goUp==0) //Otherwise, add ten.
{
*p+=10;
break;
}
}
break;
}
}
goUp=0;
*r = *p - *q; //Then subtract the number the number
*(toStore + digit) = *r; //Now store the value.
}
}
|
|
|
|
0
|
|
|
#2 | |
|
Quote:
And square brackets make array code just so much more readable. |
||
|
|
0
|
|
|
#3 |
|
Doing decimal math on a computer like we do on paper is really not the most efficient way to do this. The typically way to do it is with multibyte binary. You might want to study how we use add with carry and subtract with carry assembly instructions to do this at the assembler level. Once you understand these principles, it's easy to do it in C.
The exact details are different from one CPU to another, but here's an example explaination. http://www.pic-projects.net/index.ph...etic&Itemid=57 |
|
|
|
0
|
|
|
#4 |
|
Well,
half the point of writing this kind of stuff is to learn how debug programs and rethink the way things are done. I must admit that I find the code very difficult to follow and hence difficult to comment on. One thing that looks wrong on a quick look is one of the last lines where you do *r = *p -*q -- do check what r points at. Other things that I cannot really understand are things like: - if the two numbers has different number of "numbers", ie 1234 - 123 ? - if the result turns negative, ie 123 - 1234 ? - if one of the numbers is negative to start with ? Personally, I would scrap all of the code and restart from the beginning. Start with how you represent different size numbers and how you represent negative numbers. // gunnar ---------- This line looks wrong to me, not really understanding things. p = &number[digit+goUp]; //Goes to the next digit Should it not be [digit - goUp] as digit starts out pointing to the last in the array ? //Gunnar |
|
|
|
0
|
|
|
#5 | |
|
Quote:
Code:
*r = *p -*q EDIT: Finally solved subtraction, but my question is how come you can't multiply pointers? Last edited by jsmwoolf; Oct 7, 2011 at 09:37 PM. |
||
|
|
0
|
|
|
#6 | |
|
Quote:
A pointer has the value of an address in memory. Using street addresses as an analogy, you could for example subtract your address from a neighbor's to get some idea of how far apart your houses are on the same street. However if you live on Maple and I live across town on Davis, such a comparison quickly loses meaning. Now try multiplying your address with your neighbor's address. Could you perhaps get a value equal to another address on your street? Perhaps in rare cases. More likely than not you'll get a number that couldn't possibly be in the range of addresses on your street. There are many restrictions on pointer arithmetic. But they are not restrictions for restrictions' sake if you think about what each individual operation means. |
||
|
|
0
|
|
|
#7 | |
|
Quote:
I store a value in array[1] which has a value of 1. Code:
array[1]=1; Code:
int *p; p = &array[1]; Code:
int *q; array[2]=2; p = &array[2]; Code:
int *r; array[3]=0; r=&array[3]; *r=*p+*q; Code:
array[3]=*r; //or int n =3; *(array+n) = *r; |
||
|
|
0
|
|
|
#8 |
|
You can absolutely multiply dereferenced pointers as long as the destination points somewhere.
Edit: Having quickly looked at the first post I have to ask why you use pointers at all? It's not necessary, and will only obfuscate what you are trying to achieve and add potential for unnoticed errors. Last edited by subsonix; Oct 7, 2011 at 11:21 PM. |
|
|
|
0
|
|
|
#9 |
|
Well, now I can't remove them for subtract because it's dependent on those pointers and if I remove them, I'll get the wrong result. For addition, I removed all reference of pointers and therefore the result is left unchanged.
I was using pointers because I was grabbing digits one by one in an array that was being passed into a function. |
|
|
|
0
|
|
|
#10 | |
|
Quote:
Edit: actually *p, *q, *r all point to the very parameters you pass to the function, you might as well use them directly. Last edited by subsonix; Oct 8, 2011 at 12:03 AM. |
||
|
|
0
|
|
|
#11 |
|
You are suggesting using array syntax on pointers? Where, say, *p is equivalent to p[0] ? But that would be too simple. The arguments could be passed as pointers and just indexed directly.
__________________
Mr. Paul, sir, I thought you should be advised, there seems to be a zombie tribble clinging to your head, for it is scarfing your brain
|
|
|
|
0
|
|
|
#12 | |
|
Quote:
![]() The arguments are passed as pointers, whether they are used as arrays or not does not matter. My point was that there is not reason to have an extra set of pointers inside the function. But the question came up about multiplying pointers and while the following works, it's just ugly. Code:
*a = *b * *c; |
||
|
|
0
|
|
|
#13 | |
|
Quote:
"add" takes two numbers and adds their sum. "adc" = "add with carry" takes two numbers and the carry bit, which is either 0 or 1, and adds them. If the result is too large, it produces the partial result and sets the carry flag to 1, otherwise it sets the carry flag to 0. The x86 processors also have two instructions for subtracting: "sub" takes two numbers and calculates the difference. "sbb" = "subtract with borrow" takes two numbers and the "borrow" bit, which is either 0 or 1. It calculates the first number minus the second number minus the borrow bit. If the result is >= 0, it then sets the borrow bit to 0, otherwise it sets the borrow bit to 1. Now an example: 612 - 129. Start with borrow bit = 0. 2 - 9 - borrow 0 = -7, add 10 makes 3, borrow = 1. 1 - 2 - borrow 1 = -2, add 10 makes 8, borrow = 1. 6 minus 1 minus borrow 1 = 4, makes 4, borrow = 0. Result = 612 - 129 = 483. |
||
|
|
0
|
|
|
#14 | |
|
Quote:
You don't need to know an assembly language, you just need to be able to understand how it works. The link I posted steps through the assembly line by line with plenty of explanation. |
||
|
|
0
|
|
|
#15 |
|
What you need is basically a ripple-carry adder, but in software. This will allow you to perform addition and subtraction for arbitrary length numbers byte-by-byte.
If you do that then subtraction is as simple as making one of the numbers negative by 2's complement and feeding that into the adder. |
|
|
|
0
|
|
|
#16 | |
|
Quote:
I think it's also worth linking to Subtraction algorithms. I don't know how the OP learned to do subtraction in elementary school, but I would bet that the algorithm coded wasn't it. |
||
|
|
0
|
|
|
#17 | ||
|
Quote:
Code:
movf A0 W Code:
movf A0,W
addwf R0,F
movf A1,W
btfsc STATUS,C
incfsz A1,W
addwf R1,F
Also, if I do understand the example, do I need to go to the low-level of C and actually use binary(<<(left binary shift), >>(right binary shift), ~(switch or something), &(and), |(or), ^(XOR))? Quote:
EDIT: MOVF moves the data into another bit and resets the value to zero in the template bit(the Ax), ADDWF then takes two of the argument and then stores the final value into the second argument, INCFSZ increments the value in loops. But what's btfsc? Is it your "If..." statement? Last edited by jsmwoolf; Oct 8, 2011 at 10:03 PM. |
|||
|
|
0
|
|
|
#18 | |
|
Quote:
My code was three lines to implement the loop and initialize "borrow", and three lines for implementing the "subtract with borrow" operation. Code for adding would very much look the same. |
||
|
|
0
|
|
|
#19 | |
|
Quote:
Did you read the description of "Method of complements" I linked to? Neither of them are difficult or complex. If I'm questioning anything, it's your design skills. You seem to frequently leap to conclusions, overcomplicate things, and not do basic research, such as searching for Subtraction Algorithms. Instead of doing the basics, and getting a firm grounding in them, you seem to start coding whatever you first think of, even if you don't know the basics. This pattern has occurred over and over, with almost every problem you've posted to the list. In short, the lack of basic research and basic design is the main cause of your coding difficulties. And again, I would like to know what subtraction algorithm you learned in elementary school. I will bet it wasn't the algorithm in the code you wrote. If you can't describe the algorithm you learned, I suggest spending some time to do so. The ability to dissect procedures and express algorithms is a fundamental skill to all of programming. Equally, the ability to read and understand algorithms, then code them correctly, is another fundamental skill. I would also like to see your code that results from implementing the basic grade-school algorithm described in the link already provided. If you do it, you should find that it's essentially subtract-with-borrow. Many manual arithmetic algorithms have been refined over centuries or even millenia. If you understand the algorithm, you will often find that coding it produces simple, effective code. There's a reason for this: manual calculation is expensive, so anything that can improve it effectively will be a benefit. Last edited by chown33; Oct 9, 2011 at 11:16 AM. |
||
|
|
0
|
|
|
#20 | |
|
Quote:
In binary sense, you would have to use ~ in order to get the complement. However, would you have to grab a decimal complement by converting to binary and use ~? However, will I need to still use an array because I need to do a certain number of times in the problems that I'm doing? If I don't use an array, then how can I still follow arbitrary precision without one and manipulate data? Last edited by jsmwoolf; Oct 9, 2011 at 03:35 PM. |
||
|
|
0
|
|
|
#21 | ||
|
Then it shouldn't be hard to translate it into an English description of the procedure, which should be comprehensible to a 2nd-grader. I encourage you to try doing this, as gnasher729 did with the subtract-with-borrow algorithm. To make it easy, use exactly the same operands as gnasher729 did in his example.
Quote:
The operand in the Wikipedia example is 218. Quoting the article: "The nines' complement of y (218) is 781." It's not 782. 782 would be the 10's complement of 218. Because the 10's complement of any number is the 9's-complement + 1. For comparison, look up 2's-complement and 1's-complement in binary (base-2). I think you need to reread the wikipedia article more carefully. Much more carefully. Quote:
|
|||
|
|
0
|
|
|
#22 | |
|
Quote:
Next you define what exactly a function like subtractNumbers is to do, and what its limitations are. Is it capable of subtracting 123 - 124? If yes, is it capable of subtracting -1 - 124? Or -1 - (-124)? |
||
|
|
0
|
|
|
#23 | |||||||
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
EDIT: Using the method of complement, I was able to shorten the subtract algorithm and avoid using all of those comparisons. Yet, I still didn't shorten it to six lines. Last edited by jsmwoolf; Oct 9, 2011 at 04:51 PM. |
||||||||
|
|
0
|
|
|
#24 | ||
|
Quote:
Consider the description you gave earlier (with typos fixed): Quote:
You then take one away to get 781, the 9's-complement. But why didn't you just calculate the 9's-complement directly, like the example shows? It's as if you read a simple example and can't simply follow it as given. You add complexity that simply isn't there in the original. If you're going to do the subtraction using 10's-complement, then you can eliminate the "take one away" after the first complementation, and the "add one" at the end, and calculate directly with the 10's-complement: 873 + 782 = 1655 1655 - 1000 = 655 Basic algebra should prove how that works. |
|||
|
|
0
|
|
|
#25 | |
|
Quote:
Code:
int borrow = 0;
for (int i = space - 1; i >= 0; --i) {
int difference = number [i] - number2 [i] - borrow;
toStore [i] = (difference >= 0 ? difference : difference + 10);
borrow = (difference >= 0 ? 0 : 1);
}
|
||
|
|
0
|
![]() |
|
«
Previous Thread
|
Next Thread
»
| Thread Tools | Search this Thread |
| Display Modes | |
|
|
Similar Threads
|
||||
| thread | Thread Starter | Forum | Replies | Last Post |
| Can't paste files with Lion (Finder) | Clancycoop | Mac OS X 10.7 Lion | 4 | Aug 12, 2011 05:05 PM |
| Can't Boot Into OSX or External/CD | Wung | Mac OS X | 2 | Aug 9, 2011 11:08 PM |
| Auto correction & Spell Check in iOS 5 | TheE3Guy | iPhone | 0 | Jul 23, 2011 03:41 AM |
| Help! Can't Boot into Mac! | aaronhead14 | Windows, Linux & others on the Mac | 13 | Jan 1, 2011 02:38 AM |
| can't access certain websites on my ibook G4 | martymcfly1885 | MacBook | 0 | Nov 20, 2010 11:46 AM |
All times are GMT -5. The time now is 10:12 AM.








Linear Mode

