2010-09-23 65 views
25

Tôi có thể kiểm tra xem một số có lẻ hay thậm chí sử dụng toán tử bitwise hay không. Tôi có thể kiểm tra xem một số có dương/không/âm mà không sử dụng bất kỳ câu lệnh/toán tử điều kiện nào giống như/ternary, v.v.Kiểm tra xem một số có dương hay âm bằng cách sử dụng toán tử bitwise

Có thể thực hiện tương tự bằng cách sử dụng toán tử bit và một số mẹo trong C hoặc trong C++ không?

+3

'Sân gôn mã' này có liên quan như thế nào? – meagar

+0

Khi bạn kiểm tra lẻ/thậm chí bạn có thể muốn làm một kiểm tra bitwise để loại bỏ các bộ phận (trong trường hợp trình biên dịch của bạn là như vậy câm). Nhưng ** tại sao ** để kiểm tra dấu hiệu theo cách này ??? – ybungalobill

+2

Vui lòng nêu rõ định dạng số. Số nguyên? Nổi? Loại số nguyên/phao nào? Bổ sung của hai? Ký hiệu + Độ lớn? IEEE-754? Hãy cụ thể. – sellibitze

Trả lời

14

Nếu bit cao được đặt trên số nguyên đã ký (byte, dài, v.v., nhưng không phải là số dấu phẩy động), số đó là số âm.

int x = -2300; // assuming a 32-bit int 

if ((x & 0x80000000) != 0) 
{ 
    // number is negative 
} 

thêm:

Bạn nói rằng bạn không muốn sử dụng bất kỳ điều kiện. Tôi cho rằng bạn có thể làm điều này:

int isNegative = (x & 0x80000000); 

Và sau đó bạn có thể thử nghiệm với if (isNegative).

+5

Số dấu phẩy động ngày nay có xu hướng ở định dạng IEEE, có một dấu hiệu rõ ràng. –

+0

@David: Tôi không biết điều đó. Bạn có biết bit nào là bit dấu hiệu không? –

+0

@Jim Mischel: theo trang này: http://en.wikipedia.org/wiki/Double_precision_floating-point_format, nó cũng là bit cao. –

24

Tôi có thể kiểm tra xem một số là tích cực/zero/tiêu cực mà không sử dụng bất kỳ báo cáo có điều kiện/nhà khai thác như thế nào nếu/ternary, vv

Dĩ nhiên:

bool is_positive = number > 0; 
bool is_negative = number < 0; 
bool is_zero = number == 0; 
+17

Vâng, tôi nghĩ anh ta hỏi về các nhà khai thác bitwise ... –

+8

Thực ra đây là nền tảng duy nhất độc lập. Hơn nữa, nó sẽ hiệu quả hơn kiểm tra bitwise trên ** tất cả ** nền tảng. – ybungalobill

+0

Trên thực tế có * là * một nền tảng độc lập khác: 'signbit()'. Xem câu trả lời của tôi http://stackoverflow.com/a/19279266/72176 để biết thêm. –

3

số nguyên Signed và điểm nổi thường sử dụng bit quan trọng nhất để lưu trữ các dấu hiệu vì vậy nếu bạn biết kích thước bạn có thể trích xuất thông tin từ bit quan trọng nhất. Có rất ít lợi ích khi thực hiện việc này vì một số loại so sánh sẽ cần phải được thực hiện để sử dụng thông tin này và nó cũng dễ dàng cho một bộ xử lý để kiểm tra xem có điều gì là tiêu cực vì nó là để kiểm tra xem nó có phải là như vậy hay không. không phải không. Nếu thực tế trên bộ vi xử lý ARM, việc kiểm tra bit quan trọng nhất sẽ bình thường đắt hơn kiểm tra xem nó có âm hay không.

0

Bạn có thể phân biệt giữa âm/không âm bằng cách xem bit quan trọng nhất. Trong tất cả các biểu diễn cho các số nguyên đã ký, bit đó sẽ được đặt thành 1 nếu số đó là số âm.

Không có xét nghiệm để phân biệt giữa zero và tích cực, ngoại trừ một thử nghiệm trực tiếp chống lại 0.

Để kiểm tra cho tiêu cực, bạn có thể sử dụng

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1))) 
+0

Kích thước và chiều rộng của một loại số nguyên không liên quan chặt chẽ theo nghĩa bạn đang đề xuất. Thứ hai bit quan trọng nhất của loại unsigned không nhất thiết là bit dấu: chiều rộng của loại ký tên tương ứng có thể nhỏ hơn, hoặc thậm chí nó có thể lớn hơn một chút so với loại không dấu. –

+0

@ Jens: Nói theo nghĩa vụ, bạn nói đúng và không thể xác định bit nào chứa dấu. Nhưng bạn có thể đặt tên cho một nền tảng tồn tại khi mã này không hoạt động? –

+0

Chúng rất hiếm, tôi thừa nhận, nhưng tồn tại. Thật không may bằng tiếng Đức, nhưng bạn có thể nhận được ý tưởng: http://www.schellong.de/c_padding_bits.htm. Cũng trong cuộc thảo luận này có một ví dụ thú vị: http://www.rhinocerus.net/forum/lang-c/2007-padding-bits.html –

11

Có một cuộc thảo luận chi tiết về Bit Twiddling Hacks page .

int v;  // we want to find the sign of v 
int sign; // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8). 
sign = -(v < 0); // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32): 
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1)); 
// or, for one less instruction (but not portable): 
sign = v >> (sizeof(int) * CHAR_BIT - 1); 

// The last expression above evaluates to sign = v >> 31 for 32-bit integers. 
// This is one operation faster than the obvious way, sign = -(v < 0). This 
// trick works because when signed integers are shifted right, the value of the 
// far left bit is copied to the other bits. The far left bit is 1 when the value 
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior 
// is architecture-specific. 

// Alternatively, if you prefer the result be either -1 or +1, then use: 

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then -1, else +1 

// On the other hand, if you prefer the result be either -1, 0, or +1, then use: 

sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1)); 
// Or, for more speed but less portability: 
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1)); // -1, 0, or +1 
// Or, for portability, brevity, and (perhaps) speed: 
sign = (v > 0) - (v < 0); // -1, 0, or +1 

// If instead you want to know if something is non-negative, resulting in +1 
// or else 0, then use: 

sign = 1^((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1 

// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C 
// specification leaves the result of signed right-shift implementation-defined, 
// so on some systems this hack might not work. For greater portability, Toby 
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and 
// throughout rather than assuming bytes were 8 bits long. Angus recommended 
// the more portable versions above, involving casting on March 4, 2006. 
// Rohit Garg suggested the version for non-negative integers on September 12, 2009. 
1

Điều này không thể thực hiện theo cách di động với thao tác bit trong C. Biểu diễn cho các loại số nguyên đã ký cho phép có thể nhiều hơn số bạn có thể nghi ngờ. Cụ thể là giá trị với bit dấu hiệu và nếu không thì không cần phải là giá trị cho phép đối với loại đã ký cũng như loại không dấu, nhưng cái gọi là biểu diễn bẫy cho cả hai loại.

Tất cả các phép tính với các toán tử bit mà bạn có thể thực hiện có thể dẫn đến hành vi không xác định.


Trong bất kỳ trường hợp như một số các câu trả lời khác đề nghị, điều này là không thực sự cần thiết và so sánh với < hoặc > nên đủ trong mọi hoàn cảnh thực tế, hiệu quả hơn, dễ dàng hơn để đọc ... vì vậy chỉ cần làm điều đó theo cách đó.

0

Giả sử số của bạn là a=10 (dương). Nếu bạn thay đổi aa lần, số này sẽ bằng 0.

ví dụ:

10>>10 == 0 

Vì vậy, bạn có thể kiểm tra nếu số là tích cực, nhưng trong trường hợp a=-10 (âm):

-10>>-10 == -1 

Vì vậy, bạn có thể kết hợp những người trong một if:

if(!(a>>a)) 
    print number is positive 
else 
    print no. is negative 
+1

'-10 >> -10', tôi tin, tôi sẽ -formed và '-10 >> 10' được thực hiện. –

+1

Chuyển dịch âm có hành vi * không xác định * trong C. Và nếu lớn hơn chiều rộng của int (hoặc kiểu dữ liệu của a), thì đó cũng là hành vi không xác định. –

4
#include<stdio.h> 

void main() 
{ 
    int n; // assuming int to be 32 bit long 

    //shift it right 31 times so that MSB comes to LSB's position 
    //and then and it with 0x1 
    if ((n>>31) & 0x1 == 1) { 
     printf("negative number\n"); 
    } else { 
     printf("positive number\n"); 
    } 

    getch(); 
} 
2
// if (x < 0) return -1 
// else if (x == 0) return 0 
// else return 1 
int sign(int x) { 
    // x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1 
    int x_is_not_zero = ((x | (~x + 1)) >> 31) & 0x1; 
    return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand 
} 

Đây chính xác là những gì bạn đã làm!

3

Nó là khá đơn giản

Nó có thể dễ dàng thực hiện bằng cách

return ((!!x) | (x >> 31)); 

nó trả

  • 1 cho một số dương,
  • -1 cho một tiêu cực, và
  • 0 cho số không
+0

Giả sử số nguyên 32 bit :) – AndyG

+0

@AndyG 'return ((!! x) | (x >> (8 * sizeof (int) -1)));' sẽ là một cách tốt hơn tôi nghĩ. – noufal

+0

Khi tôi đánh giá biểu thức này, cho giá trị âm của x, nó trả về 1 thay vì -1.Có thể bạn sửa lỗi của tôi: nếu x = -ve, then, (! X) = 0 => (!! x) = 1; x >> 31 = 1; Do đó ((!! x) | (x >> 31)) = (1) | (1) = (1) – piyukr

7

Hoặc, bạn có thể sử dụng signbit() và công việc được thực hiện cho bạn.

Tôi giả định rằng dưới mui xe, triển khai math.h là kiểm tra bit hiệu quả (có thể giải quyết mục tiêu ban đầu của bạn).

tham khảo: http://en.cppreference.com/w/cpp/numeric/math/signbit

0

Khi bạn chắc chắn về kích thước của một số nguyên (giả sử 16-bit int):

bool is_negative = (unsigned) signed_int_value >> 15; 

Khi bạn không chắc chắn về kích thước của các số nguyên:

bool is_negative = (unsigned) signed_int_value >> (sizeof(int)*8)-1; //where 8 is bits 

Từ khóa unsigned là tùy chọn.

1
if((num>>sizeof(int)*8 - 1) == 0) 
    // number is positive 
else 
    // number is negative 

Nếu giá trị là 0 thì số là tích cực khác tiêu cực

1

Một cách đơn giản để tìm hiểu xem một số là tích cực hay tiêu cực: Hãy để số được x kiểm tra nếu [x * (-1)]> x. nếu đúng x là âm dương khác.

0

Đây là bản cập nhật liên quan đến C++ 11 cho câu hỏi cũ này.Nó cũng đáng xem xét std::signbit.

On Compiler Explorer sử dụng gcc 7.3 64bit với tối ưu hóa O3, mã này

bool s1(double d) 
{ 
    return d < 0.0; 
} 

tạo

s1(double): 
    pxor xmm1, xmm1 
    ucomisd xmm1, xmm0 
    seta al 
    ret 

Và mã này

bool s2(double d) 
{ 
    return std::signbit(d); 
} 

tạo

s2(double): 
    movmskpd eax, xmm0 
    and eax, 1 
    ret 

Bạn sẽ cần phải cấu hình để đảm bảo rằng có bất kỳ sự khác biệt tốc độ, nhưng phiên bản ký hiệu sử dụng 1 opcode ít hơn.

Các vấn đề liên quan