How to check if a signed integer is neg or pos?

assembly, negative-integer, negative-number, x86

Solution

The value is negative if the MSB is set. The SF (sign flag) in FLAGS is set according to that bit of the result.

test eax, eax      ; set FLAGS according to the value in EAX; like cmp eax, 0
js   negative      ; jump if top bit was set in EAX

Alternatively since `test reg,reg` sets FLAGS the same way as `cmp reg,0`, you could use `jl` to jump if the value is "less than zero". That's the same thing. Fun fact: this also works as a trick for optimizing unsigned `if(eax >= 0x80000000U)`.

You can manually do it as a single-bit test (not taking advantage of SF) with a less efficient instruction (longer because it has to include the 32-bit constant.) This is a lot like your `bt eax,31` but setting ZF=0 instead of CF=1 when the sign bit is set.

test eax, 0x80000000      ; set flags according to EAX & (1<<31)
jnz  negative             ; jump if that result was non-zero, i.e. bit was set

This works for any register size, byte (int8_t), word (int16_t), dword (int32_t), or qword (int64_t). For example with bytes:

test al, al
js   is_negative
; or
test al, 80h
jne  is_negative

If the value in a register was produced by something that sets FLAGS "according to the result", like most ALU instructions such as `add ecx, edx`, you can `js` to see if it's negative or not without needing to `test ecx, ecx` first. SF is already set according to the MSB of the value in ECX, by the `add` instruction.

Terminology: positive doesn't include zero

- positive is `x > 0`. Numbers 1 or greater, not including zero. (Sometimes used loosely as the opposite of negative, but strictly speaking it's not.)

- non-negative is `x >= 0`.

- negative is `x < 0`.

- zero is not positive or negative. Its 2's complement bit-pattern is all-zero, no bits set. (x86 uses 2's complement signed integers, like all other modern CPUs. That's why there's no integer negative-zero.)

So if you want to find out if a number is positive or negative, that's two separate checks unless you already know it's non-zero. (Assuming you're using a strict definition of positive. Sometimes from context you can infer that someone means one condition, but precise terminology is useful in computing so prefer that yourself.)

Your `bt` idea could work, but x86 numbers bits from bit 0 at the bottom (least significant), to bit 31 as the sign-bit of a 32-bit register like EAX. Also, CF set means negative, so `jc negative`. But `bt` isn't faster unless you actually want the condition in the carry flag for use with `adc edx, 0` to do `negcount += (x<0)` counting negative numbers or something. Alternatively, `add eax,eax` or `shl eax,1` will shift the top bit of EAX into CF (and also modify EAX, unlike BT).

Problem

I am new to x86 assembly language, I have a signed integer saved in register `eax`, and I want to check if the number is negative or positive. To do that, I used `bt` instruction to check the first bit. Here is what I did: ``` bt eax,0 jnc isNegative ``` `bt` loads the first bit to carry flag, and I used `jnc` to check if carry flag is 0 or 1. If it's 1, it should be a negative number, and does negative instructions... however, the output is unpredictable, sometimes I have a positive and it recognize it as a negative number. Am I doing something wrong? EDIT: I just realized it could have something to do with bit numbering. It is actually checking the least significant bit instead of the first bit. Let me try using `bt eax, 31`

Original source

Related problems