Click here to Skip to main content
15,887,135 members
Please Sign up or sign in to vote.
2.25/5 (4 votes)
See more:
I'm using an ADC/DAC board with 16-bit outputs; the output voltage can be negative or positive; and the sign is set up with a separate register. The project is almost done and it worked pretty well until I checked up negative output voltage. When I measure output voltage (with a multi-meter!) it shows unexpected values.

I did not find a reason. I tried to check up each bit sent to the board individually. Here is what I got:

C#
using System;

enum Signed16Bits : ushort
{
    Bit01 = 1,
    Bit02 = 2,
    Bit03 = 4,
    Bit04 = 8,
    Bit05 = 16,
    Bit06 = 32,
    Bit07 = 64,
    Bit08 = 128,
    Bit09 = 256,
    Bit10 = 512,
    Bit11 = 1024,
    Bit12 = 2048,
    Bit13 = 4096,
    Bit14 = 8192,
    Bit15 = 16384,
    Sign = 32768
}

class Program {
    static void Main(string[] args) {

        short value5 =
        (short)(
          Signed16Bits.Bit01 |
          Signed16Bits.Bit03
        );
        Console.WriteLine("5 == {0}", value5); //output: 5 == 5

        //same as value5, but set sign bit:
        ushort signed5 =
        (ushort)(
           Signed16Bits.Bit01 |
           Signed16Bits.Bit03 |
           Signed16Bits.Sign
        );
        short minus5 = (short)signed5;

        Console.WriteLine("-5 == {0}", minus5); //output: -5 == -32763;
        //why!!!???
    }
} 



I cannot explain that. I know that last bit in a signed integer is a sign bit. If I flip a sign bit, the integer should change its sign. Why on earth it changes the absolute value?! Is something wrong in this code? How can I work around?

Thank you very much in advance.

[edit]Urgency removed - OriginalGriff[/edit]
Posted
Updated 31-Dec-10 23:06pm
v2
Comments
OriginalGriff 1-Jan-11 5:05am    
Don't say "It's Urgent!" in a question - it just annoys people because they assume you have been too lazy to do it in time! This normally means you get a slower response... :laugh:
OriginalGriff 2-Jan-11 3:43am    
Answer updated

It's fairly simple, but lets make it simpler and look at it as if it was a three bit integer, with the top bit (bit 2) being the sign bit:
BIN   DEC
000 =  0
001 =  1
010 =  2
011 =  3
100 = -4
101 = -3
110 = -2
111 = -1
So when you reduce zero by one, you get all ones, and this is minus one in decimal.
Flipping the sign bit does not reverse the sign.

"Sorry, I just tested your example on two integer types: byte and unsigned byte. In both cases:
100 = 4
101 = 5
110 = 6
111 = 7
Besides, how can possibly it make any sense: a jump from 3 to -4. Why?! - programmer095 13 hrs ago"



Read what I said again: lets make it simpler and look at it as if it was a three bit integer


An int in C# is a 32 bit integer, so it follows rules for binary right up to 2 Gig!

For 32 bit numbers:
Dec Bin
 0  00000000000000000000000000000000
 1  00000000000000000000000000000001
 2  00000000000000000000000000000010
 3  00000000000000000000000000000011
 4  00000000000000000000000000000100
...
-1  11111111111111111111111111111111
-2  11111111111111111111111111111110
-3  11111111111111111111111111111101
...
Which is a little difficult to read: hence the imaginary three bit integer!

A byte is 7 bits plus sign (or 8 for unsigned) so the range of +127 to -128 is a little large to expand as well...


[edit]Added byte info - it's early, and I'm still on my first coffee...-OriginalGriff[/edit]
 
Share this answer
 
v3
Comments
programmer095 1-Jan-11 13:41pm    
Sorry, I just tested your example on two integer types: byte and unsigned byte. In both cases:
100 = 4
101 = 5
110 = 6
111 = 7
Besides, how can possibly it make any sense: a jump from 3 to -4. Why?!
Sergey Alexandrovich Kryukov 2-Jan-11 16:28pm    
I think, this is pretty good clarification. I have no idea what programmer095 fails to understand (Sorry, programmer095: what a stubborn preoccupation with straightforward and wrong ideas! You really should accept the answer by now).
Look into this article for understanding the phenomenon : http://en.wikipedia.org/wiki/Two's_complement[^]

Quote from the article :
The two's-complement system has the advantage of not requiring that the addition and subtraction circuitry examine the signs of the operands to determine whether to add or subtract. This property makes the system both simpler to implement and capable of easily handling higher precision arithmetic. Also, zero has only a single representation, obviating the subtleties associated with negative zero, which exists in ones'-complement systems.


Your issue is the assumption that a single bit-flip (the sign bit) will negate the value. That is not true.

Cheers
 
Share this answer
 
v2
Comments
programmer095 1-Jan-11 13:44pm    
Thank you very much. I'm looking at this article: is it about some real machine? And why they do such complex calculations? just to make CPU working slowly? And I still does not understand how this trick is related to my question, sorry...
Sergey Alexandrovich Kryukov 1-Jan-11 14:41pm    
Estys, this reference is good; the reading should help anyone to understand the issue (which is not an issue at all if you know it) - my 5.
As to the author of this question (kind of interesting), the situation looks like almost hopeless.
Andreas Gieriet 2-Jan-11 17:24pm    
[edit]To programmer095 (not estys):[/edit] the term "sign-bit" is a way to *deduce* if the two's complement number is negative or positive - it does *not* mean that this is the sign and the rest is the positive number. Please accept the two's complement as a carefully engineered representation which is *the* way CPUs natively handle their integral numbers. That's freshman lecture 1 for digital electronics.
Manfred Rudolf Bihy 2-Jan-11 18:20pm    
@Andreas: You are barking up the wrong tree, Estys is the one doing all the explaining and your comment can only be directed at OP (aka programmer095). Pay attention!
Sergey Alexandrovich Kryukov 3-Jan-11 3:03am    
Estys, no one could possibly give better argument (but DaveyM69 made another great point about separate redundant bit maps for +0 and -0, which is avoided with two's-complement system).
I am sorry I am unable to vote 5 several times :-)

I am truly amazed with you patience. I almost lost mine. All of a sudden I guessed what was the root of the problem (DAC), so programmer095 accepted the answer, to some of my surprise. This member really needs to learn how to read and understand things (if it even possible). Wow!
"Flipping" the most significant bit does not convert the number from + to -.

Hex      Dec      Bin
0x7FFF =  32767 = 0111 1111 1111 1111
0x0000 =  0     = 0000 0000 0000 0000
0xFFFF = -1     = 1111 1111 1111 1111
0x8FFF = -32768 = 1000 0000 0000 0000


This little test code demonstrates:
C#
WriteLine(short.MaxValue);
WriteLine(0);
WriteLine(-1);
WriteLine(short.MinValue);

public static void WriteLine(short value)
{
    Console.WriteLine(
    "0x{0} | {1} | {2}",
    Convert.ToString(value, 16).PadLeft(4, '0'),
    value,
    Convert.ToString(value, 2).PadLeft(16, '0'));
}
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 3-Jan-11 3:07am    
Great point about +0 and -0 (see my comment on your comment to my answer). I voted "5" and sorry I cannot vote more 5s :-)
All of a sudden, I've realized what else could be wrong.

Let's try this. I noticed you mentioned: "the sign is set up with a separate register". May be, this is a key. Chances are, your ADC/DAC board cannot work with two's-complement arithmetic (please see the reference given by Estys once again). I don't know exactly why, it does not matter. Maybe, this way is easier for the controller's firmware or something.

So, let's see what could have happened. First, you tried normal CPU arithmetic and sent a negative value (bit mapped according to two's-complement schema) to the controller. No wonder, if controller uses something different (not two's-complement) schema, it generates wrong voltage.

Later on, you were thinking about you schema which is the same as of unsigned value plus separate sign bit, exactly what you assumed in your question. But did you try to send your number obtained with the help of your Signed16Bits.Sign member to the controller?!

Probably, you have done exactly the opposite. You kept trying your bit-flipping schema with your computer's CPU and naturally got wrong results. You should have used it with your controller. Instead, you tested your controller with two's-complement values (without understanding that) and got wrong voltages.

Please try it and report back the results. Is my idea right?

But if it is, you've done misleading discussion and did not tell us all the facts. Instead of asking more and more stupid..., well, interesting but not always absolutely relevant questions, you should have tested your flipped-bit values on your controller.

And, by the way, if it works for you, please don't forget to accept it and credit other answers -- they are quite good, despite of your misleading questions and comments!

Good luck!
 
Share this answer
 
v2
Comments
programmer095 2-Jan-11 18:10pm    
Yes, of course! I've tried this recently before looking at your answer. But the answer is correct. This is simple. The manual of the board is hard to understand. Of course I will accept the answer. Thank you.
I still think this two's complement is weird. Flipping bit is just one bit operation. Comparing two absolute value is easy, just compare all buts except sign bit. Why flipping so many bits for just a negation operation? Who designed such thing? Are all the processors so weird? What DAC does is right, what processor does is just to confuse me, what else?
DaveyM69 2-Jan-11 19:48pm    
@programmer095: This is the way all processors work (as far as I know). It makes sense really. 0x0000 - 1 must be 0xFFFF so therefore for a signed 16bit value 0xFFFF must be -1.
Also, using your theory there would be 1 less value available (-32768), and there would be +0 and -0 instead...
Sergey Alexandrovich Kryukov 3-Jan-11 3:06am    
DaveyM69,

Great point about +0 and -0. This should be a final decisive point in the discussion. We hardly could give more arguments. Thank you.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900