i know unsigned,two's complement, ones' complement and sign magnitude, and the difference between these, but what i'm curious about is:
why it's called two's(or ones') complement, so is there a more generalize N's complement?
in which way did these genius deduce such a natural way to represent negative numbers?
Two's complement came about when someone realized that 'going negative' by subtracting 1 from 0 and letting the bits rollunder actually made signed arithmetic simpler because no special checks have to be done to check if the number is negative or not. Other solutions give you a discontinuity between -1 and 0. The only oddity with two's complement is that you get one more negative number in your range than you have positive numbers. But, then, other solutions give you strange things like +0 and -0.
According to Wikipedia, the name itself comes from mathematics and is based on ways of making subtraction simpler when you have limited number places. The system is actually a "radix complement" and since binary is base two, this becomes "two's complement". And it turns out that "one's complement" is named for the "diminished radix complement", which is the radix minus one. If you look at this for decimal, the meanings behind the names makes more sense.
Method of Complements (Wikipedia)
You can do the same thing in other bases. With decimal, you would have 9's complement, where each digit X is replaced by 9-X, and the 10's complement of a number is the 9's complement plus one. You can then subtract by adding the 10's complement, assuming a fixed number of digits.
An example - in a 4 digit system, given the subtraction
0846
-0573
=0273
First find the 9's complement of 573, which is 9-0 9-5 9-7 9-3 or 9426
the 10's complement of 573 is 9426+1, or 9427
Now add the 10's complement and throw away anything that carries out of 4 digits
0846
+9427 .. 10's complement of 573
= 10273 .. toss the 'overflow' digit
= 0273 .. same answer
Obviously that's a simple example. But the analogy carries. Interestingly the most-negative value in 4-digit 10's complement? 5000!
As for the etymology, I'd speculate that the term 1's complement is a complement in the same sense as a complementary angle from geometry is 90 degrees minus the angle - i.e., it's the part left over when you subtract the given from some standard value. Not sure how "2's" complement
makes sense, though.
In the decimal numbering system, the radix is ten:
radix complement is called as ten's complement
diminished radix complement is called as nines' complement
In the binary numbering system, the radix is two:
radix complement is called as two's complement
diminished radix complement is called as ones' complement
Source: https://en.wikipedia.org/wiki/Method_of_complements
I've been doing a lot of reading on this lately. I could be wrong, but I think I've got it...
The basic idea of a complement is straightforward: it's the remaining difference between one digit and another digit. For example, in our regular decimal notation, where we only have ten digits ranging from 0 to 9, we know that the difference between 9 and 3 is 6, so we can say that "the nines' complement of 3 is 6".
From there on out, there's something that I find gets easily confused, with very little help online: how we choose to use these complements to achieve subtraction or negative value representation is up to us! There are multiple methods, with two majorly accepted methods that both work, but with different pros and cons. The whole point of the complements is to be used in these methods, but "nine's complement" itself is not a subtraction or negative sign representation method, it's just the difference between nine and another digit.
The old-style "nines' complement" way of flipping a decimal number (nines' complement can also be called the "diminished radix complement" in the context of decimal, because we needed to find a complicated fancy way to say it's one less than ten) to perform addition of a negative value worked fine, but it gave two different values for 0 (+0 and -0), which was an expensive waste of memory on computing machines, and it also required additional tools and steps for carrying values, which added time or resource.
Later, someone realized that if you took the nines' complement and added 1 afterwards, and then dropped any carrying values beyond the most significant digit, you could also achieve negative value representation or subtraction, while only having one 0 value, and not needing to perform any carry-over at the end. (The only downside was that your distribution of values was uneven across negative and positive numbers.) Because the operation involved taking nines' complement and adding one to it, we called it "ten's complement" as a kind of shorthand. Notice the different placement of the apostrophe in the name. We have two different calculations that use the same name. The method "ten's complement" is not the same as "tens' complement". The former uses the second method I mentioned, while the latter uses the first (older) method I mentioned.
Then, to make the names simpler later, we said, "Hey, we call it ten's complement and it flips a base 10 number (decimal representation), so when we're using it we should just call it the "radix complement". And when we use nines' complement in base 10 we should just call it the "diminished radix complement". Again, this is confusing because we're reversing the way it actually happened in our terminology... ten's complement was actually named because it was "nines' complement plus one", but now we're calling it "ten's complement diminished" basically.
And then the same thing applies with ones' complement and two's complement for binary.
Related
In Elements of Programming Interviews in Java, the authors say: "Writing a program to count the number of bits that are set to 1 in a nonnegative integer is a good way to get up to speed with primitive types".
Why do they qualify this with 'nonnegative'?
Non-negative means positive or zero.
You are assumed to use shifts and bit operations.
Bit shifts can be sign-extending, which can be misleading. To avoid this issue, you are asked to handle non-negative values only.
But you can handle negative values too, if you want. Java has unsigned shifts >>>.
Sure this is an exercise. In real code you'll use a library implementation. java.lang.Integer has bitCount(int i). I assume bitCount will execute on a hardware as bit-counting instruction, such as x86 popcnt, so it should be better than manual bit manipulation, or at least use a very decent bit manipulation implementation rather than one you'd write as an exercise. There's a whole tag hammingweight about counting those bits.
Negative integers are stored a little bit differently.
In a 4 Bit signed integer, 1111b would be -1, whereas 1000b would be -8, making the count of 1's dependent on the number of bits in the number. That way you can't answer the question anymore.
What would be the most efficient way to grab the, say, 207th decimal place of a number? Would it just be x * Math.pow(10,207) % 10?
How's this for python
int((x*(10**n)))%10
What you want is impossible.
The only things in java that work with Math.pow and basic operators are the primitives. The only floating point primitives are float and double. These are IEEE754 floating point numbers; doubles are 64 bits and floats are 32 bits.
A simple principle applies: If you have 64 bits, then you can only represent 2^64 different numbers (it's actually a little less). So, you get about 18446744073709551616 numbers, of all numbers in existence, which actually exist as far as the computer is concerned for doubles. all other numbers do not exist.
So what happens if a mathematical operation (say, 0.1 + 0.2) ends up being a number that doesn't exist? Well, java (this is predicated by the IEEE754 standard; most languages and chips do it this way) will return you the nearest number amongst all the 18446744073709551616 numbers that do exist.
The problem with wanting the 207th digit is that obviously, given that only 18446744073709551616 numbers exist, none of those 18446744073709551616 numbers have that kind of precision. Asking for the 207th digit is therefore completely random. It says nothing about the input number... whatsoever.
Let me repeat that: There are no double values that have a significant 207th digit AT ALL.
If you want 'perfect' representation, with no rounding whatsoever, you want BigDecimal, but note that demanding perfection is tricky. Imagine in basic decimal math (computers are binary, but lets stick with decimal as we're all much more familiar with it, what with our 10 fingers and all), I ask you to only give me perfect answers, and then I ask you to divide 1 by 3.
BigDecimal won't let you do that either, so the ops you can run on BigDecimals without telling BigDecimal in what ways it is allowed to be inprecise leads to exceptions.
If you've set it all up exactly how you wanted it, and you really have a BigDecimal with a 207th digit after the comma, you can use the scale feature, or just the power-of-10 feature to get what you want.
Note BigDecimal is not primitive and therefore does not support the +, %, etc operators.
***Special Note: There is no: "This will handle all situations" answer here as the arbitrary value such as 207 could take the calculations way outside the bounds of possible precision of the variable types involved. My answer as such will only work within the bounds of variable type precision for which 207 is really not possible...
To get the specific digit an arbitrary number (like 207) of places after the decimal point... if you just multiply by factor of 10.. and then take mod 10, the answer (in java) is still a floating point type... not a single digit...
To get a specific digit an arbitrary number (n) of places after the decimal point, without converting to string:
Math.floor(x*Math.pow(10,n)) % 10;
to get 4th digit after 2.987654321
x*Math.pow(10, 4) = 29876.54321
Math.floor(29876.54321) = 29876
29876 % 10 = 6
In Java, a variable of type int is represented internally as a 32-bit signed integer. Suppose that one bit stores the sign, and the other 31 bits store the magnitude of the number in base 2. In this scheme, what is the largest value that can be stores as type int?
The answer is (2^31)-1. I am curious to what the purpose of the -1 is? Why does 1 have to be subtracted from the magnitude of the number? I don't believe the 1 has anything to do with the sign because that is what the 32nd bit is for.
You are forgetting the 0.
In a decimal system, with a singe digit you are able to store 10 values and largest value is 9 (which is 10^1 - 1).
This is the same story. With a i digits number in base b you are able to store b^i values and the largest one is b^i-1 (I'm ignoring the sign bit right now).
As a side note: the representation used by numbers in Java (as in many other implementations) is the two's complement which has the peculiarity of storing just a 0 (otherwise you would end up having two 0's: -0 and +0 according to the first bit for the sign). So even if the largest value is 2^31-1, the smallest one is -2^31.
You should learn about two's complement notation. All java integer types are signed, and all use this to represent whole numbers. It is very nice, because you never need to subtract.
This is in reference to the comments in this question:
This code in Java produces 12.100000000000001 and this is using 64-bit doubles which can present 12.1 exactly. – Pyrolistical
Is this true? I felt that since a floating point number is represented as a sum of powers of two, you cannot represent 12.1 exactly, no matter how many bits you have. However, when I implemented both the algorithms and printed the results of calling them with (12.1, 3) with many significant digits, I get, for his and mine respectively:
12.10000000000000000000000000000000000000000000000000000000000000000000000000
12.10000000000000100000000000000000000000000000000000000000000000000000000000
I printed this using String.format("%76f"). I know that's more zeros than necessary, but I don't see any rounding in the 12.1 .
No. As others noted in followups to his comment, no sum of (a finite number of) powers of two can ever add up to exactly 12.1. Just like you can't represent 1/3 exactly in base ten, no matter how many digits you use after the decimal point.
In binary, 12.1 is:
1100.000110011001100110011...
Since this doesn't terminate, it can't be represented exactly in the 53 significand bits of a double, or any other finite-width binary floating-point type.
Try to express 0.1 in binary:
0.5 is too big
0.25 is too big
0.125 is too big
0.0625 fits, and leaves a remainder of 0.0375
0.03125 fits, and leaves a remainder of 0.00625
0.015625 is too big
0.0078125 is too big
0.00390625 fits, and leaves a remainder of 0.00234375
0.001953125 fits, and leaves a remainder of 0.000390625
It's going to keep repeating indefinitely, creating a base 2 value of 0.00011001100...
No, it can't be expressed exactly in a double. If Java supports BCD, or fixed point decimal, that would work exactly.
Not in binary, no. If you'll allow me to be fanciful, you could in "floating point binary coded decimal" (which, to the best of my knowledge, has never been implemented):
12.1 = 0000 . 0001 0010 0001 * (10^2)
In binary all non-zero values are of the form 1.xyz * m, and IEEE form takes advantage of this to omit the leading 1. I'm not sure what the equivalent is for FP-BCD, so I've gone for values of the form 0.xyz * m instead.
I suggest reading What Every Computer Scientist Should Know About Floating Point Arithmetic. Then you'll know for sure. :)
A way to see what the double is fairly exactly is to convert it to BigDecimal.
// prints 12.0999999999999996447286321199499070644378662109375
System.out.println(new BigDecimal(12.1));
Yes, you can exactly represent 12.1 in floating point.
You merely need a decimal floating point representation, not a binary one.
Use the BigDecimal type, and you'll represent it exactly!
No, the decimal number 12.1 cannot be represented as a finite (terminating) binary floating-point number.
Remember that 12.1 is the rational number 121/10. Note that this fraction is in lowest terms (cannot be reduced by removing common fators of the numerator an denominator).
Suppose (in order to reach a contradiction) that 121/10 could be written also as n / (2**k) where n and k are some positive integers, and 2**k denotes the kth power of two. We would have a counter-example to unique factorization. In particular
10 * n == 2**k * 121
where the left-hand side is divisible by 5 which the right-hand side is not.
One option that you can use is to not store v=0.1, but instead store v10=1. Just divide by 10 when needed ( the division will create truncation error in your result but v will still be OK )
In this case you're basically doing a fixed point hack, but keeping the number in a float.
But its usually not worth doing this unless you really have to.
I heard C, C++, Java uses two complements for binary representation. Why not use 1 complement? Is there any advantage to use 2 complement over 1 complement?
Working with two's complement signed integers is a lot cleaner. You can basically add signed values as if they were unsigned and have things work as you might expect, rather than having to explicitly deal with an additional carry addition. It is also easier to check if a value is 0, because two's complement only contains one 0 value, whereas one's complement allows one to define both a positive and a negative zero.
As for the additional carry addition, think about adding a positive number to a smallish negative number. Because of the one's complement representation, the smallish negative number will actually be fairly large when viewed as an unsigned quantity. Adding the two together might lead to an overflow with a carry bit. Unlike unsigned addition, this doesn't necessarily mean that the value is too large to represent in the one's complement number, just that the representation temporarily exceeded the number of bits available. To compensate for this, you add the carry bit back in after adding the two one's complement numbers together.
The internal representation of numbers is not part of any of those languages, it's a feature of the architecture of the machine itself. Most implementations use 2's complement because it makes addition and subtraction the same binary operation (signed and unsigned operations are identical).
Is this a homework question? If so, think of how you would represent 0 in a 1's complement system.
The answer is different for different languages.
In the case of C, you could in theory implement the language on a 1's complement machine ... if you could still find a working 1's complement machine to run your programs! Using 1's complement would introduce portability issues, but that's the norm for C. I'm not sure what the deal is for C++, but I wouldn't be surprised if it is the same.
In the case of Java, the language specification sets out precise sizes and representations for the primitive types, and precise behaviour for the arithmetic operators. This is done to eliminate the portability issues that arise when you make these things implementation specific. The Java designers specified 2's complement arithmetic because all modern CPU architectures implement 2's complement and not 1's complement integers.
For reasons why modern hardware implements 2's complement and not 1's complement, take a look at (for example) the Wikipedia pages on the subject. See if you can figure out the implications of the alternatives.
At least C and C++ offer 1's complement negation (which is the same as bitwise negation) via the language's ~ operator. Most processors - and all modern ones - use 2's complement representation for a couple reasons:
Adding positive and negative numbers is the same as adding unsigned integers
No "wasted" values due to two representations of 0 (+0 and -0)
Edit: The draft of C++0x does not specify whether signed integer types are 1's complement or 2's complement, which means it's highly unlikely that earlier versions of C and C++ did specify it. What you have observed is implementation-defined behavior, which is 2's complement on at least modern processors for performance reasons.
Almost all existing CPU hardware uses two's complement, so it makes sense that most programming languages do, too.
C and C++ support one's complement, if the hardware provides it.
It has to do with zero and rounding. If you use 1st complement, you can end up have two zeros. See here for more info.
Sign-magnitude representation would be much better for numeric code. The lack of symmetry is a real problem with 2's complement and also precludes a lot of useful (numeric orientated) bit-hacks. 2's complement also introduces trick situations where an arithmetic operation may not give you the result you think it might. So you must be mindful with regards to division, shifting and negation.