2009-03-31 41 views
13

Tôi đang sử dụng một mẫu nổi tiếng cho phép hằng nhị phânC++ liên tục nhị phân/đen

template< unsigned long long N > 
struct binary 
{ 
    enum { value = (N % 10) + 2 * binary<N/10> :: value } ; 
}; 

template<> 
struct binary<0> 
{ 
    enum { value = 0 } ; 
}; 

Vì vậy, bạn có thể làm một cái gì đó giống như nhị phân < 101.011.011> :: giá trị. Thật không may điều này có một giới hạn 20 chữ số cho một unsigned dài dài.

Có ai có giải pháp tốt hơn không?

+0

Giới hạn 20 có thể phụ thuộc vào trình biên dịch. Nó phụ thuộc vào bao nhiêu mẫu đệ quy nó sẽ chịu đựng được. Một số trình biên dịch hiện đại sẽ cho phép bạn vượt qua trong một đối số để thiết lập độ sâu đệ quy mẫu tối đa. –

+3

Tôi mặc dù giới hạn là do số chữ số thập phân bạn có thể lưu trữ trong một unsigned long dài, vì nó về cơ bản lấy số thập phân * 101011011 và biến thành nhị phân, có? – paxdiablo

+0

Pax: có, ít nhất là cho GCC mà tôi đang sử dụng. – Unknown

Trả lời

25

Liệu công việc này nếu bạn có một số không hàng đầu về giá trị nhị phân của bạn? Một số không đầu làm cho bát phân không đổi thay vì số thập phân.

Dẫn đến cách nào để ép thêm vài chữ số ra khỏi giải pháp này - luôn bắt đầu hằng số nhị phân của bạn với số không! Sau đó thay thế 10 trong mẫu của bạn với 8.

+2

Ooh, đó là lén lút :-) Bravo. – paxdiablo

+1

Cảm ơn các bạn, bạn đã thực hiện đêm của tôi! –

4

C++ 0x có user-defined literals, có thể được sử dụng để triển khai những gì bạn đang nói đến.

Nếu không, tôi không biết cách cải thiện mẫu này.

+0

Bạn có thể đưa ra một ví dụ không. – Unknown

+0

chắc chắn, đây là một ví dụ: http://stackoverflow.com/questions/537303/binary-literals/538101#538101 –

5

Các phương pháp tôi đã luôn sử dụng, mặc dù không thanh lịch như của bạn:

1/Chỉ cần sử dụng hex. Sau một thời gian, bạn chỉ cần biết những chữ số thập phân nào đại diện cho các mẫu bit nào.

2/Sử dụng hằng số và HOẶC hoặc THÊM chúng. Ví dụ (có thể cần vòng loại trên các mẫu bit để làm cho họ unsigned hoặc dài):

#define b0 0x00000001 
#define b1 0x00000002 
: : : 
#define b31 0x80000000 

unsigned long x = b2 | b7 

3/Nếu hiệu suất là không quan trọng và khả năng đọc rất quan trọng, bạn chỉ có thể làm điều đó trong thời gian chạy với một chức năng như "x = fromBin (" 101011011 ");".

4/Là giải pháp lén lút, bạn có thể viết tiền xử lý đi qua tệp * .cppme của bạn và tạo các tệp * .cpp bằng cách thay thế tất cả các chuỗi "0b101011011" bằng "0x15b" tương đương của chúng dây). Tôi sẽ không làm điều này một cách nhẹ nhàng vì có nhiều loại cú pháp phức tạp mà bạn có thể phải lo lắng. Nhưng nó sẽ cho phép bạn viết chuỗi của bạn như bạn muốn mà không cần phải lo lắng về những bất thường của trình biên dịch, và bạn có thể giới hạn sự phức tạp của cú pháp bằng cách mã hóa cẩn thận.

Tất nhiên, bước tiếp theo sau đó sẽ được vá GCC để nhận ra "0b" hằng số nhưng điều đó có thể là một :-) overkill

+0

funny bạn đã đề cập đến phần cuối cùng. Tôi cũng đang sử dụng bitet <> (string (str)). To_ulong() – Unknown

+2

Tôi tự hỏi tình hình là gì khi sử dụng 'mẫu nhị phân' tốt hơn so với các hằng số hex đơn giản hoặc 'or-ing' cùng với các tên thích hợp cho các bit nếu bạn đang lập mô hình giao thức phần cứng hoặc giao tiếp? –

+0

Trên thực tế GCC hỗ trợ hằng số 0b. –

3

Bạn có thể thêm các tham số không kiểu mẫu để "mô phỏng" thêm bit:

// Utility metafunction used by top_bit<N>. 
template <unsigned long long N1, unsigned long long N2> 
struct compare { 
    enum { value = N1 > N2 ? N1 >> 1 : compare<N1 << 1, N2>::value }; 
}; 

// This is hit when N1 grows beyond the size representable 
// in an unsigned long long. It's value is never actually used. 
template<unsigned long long N2> 
struct compare<0, N2> { 
    enum { value = 42 }; 
}; 

// Determine the highest 1-bit in an integer. Returns 0 for N == 0. 
template <unsigned long long N> 
struct top_bit { 
    enum { value = compare<1, N>::value }; 
}; 

template <unsigned long long N1, unsigned long long N2 = 0> 
struct binary { 
    enum { 
     value = 
      (top_bit<binary<N2>::value>::value << 1) * binary<N1>::value + 
      binary<N2>::value 
    }; 
}; 

template <unsigned long long N1> 
struct binary<N1, 0> { 
    enum { value = (N1 % 10) + 2 * binary<N1/10>::value }; 
}; 

template <> 
struct binary<0> { 
    enum { value = 0 } ; 
}; 

Bạn có thể sử dụng như trước đây, ví dụ:

binary<1001101>::value 

Nhưng bạn cũng có thể sử dụng sau các hình thức tương đương:

binary<100,1101>::value 
binary<1001,101>::value 
binary<100110,1>::value 

Về cơ bản, tham số bổ sung cung cấp cho bạn 20 bit khác để phát. Bạn có thể thêm nhiều tham số hơn nếu cần.

Bởi vì giá trị địa điểm của số thứ hai được sử dụng để tìm ra số lượng đầu tiên cần phải di chuyển đến đâu, số thứ hai phải bắt đầu bằng 1. (Điều này là bắt buộc, kể từ khi bắt đầu bằng một 0 sẽ làm cho số được hiểu là số bát phân.)

3
template<unsigned int p,unsigned int i> struct BinaryDigit 
{ 
    enum { value = p*2+i }; 
    typedef BinaryDigit<value,0> O; 
    typedef BinaryDigit<value,1> I; 
}; 
struct Bin 
{ 
    typedef BinaryDigit<0,0> O; 
    typedef BinaryDigit<0,1> I; 
}; 

phép:

Bin :: O :: Tôi :: Tôi :: O :: O :: trị

nhiều tiết hơn, nhưng không có giới hạn (cho đến khi bạn nhấn kích thước của một int không dấu của khóa học).

+0

Lén lút! nhưng sẽ không quá nhiều thay vì chỉ cần gõ hex? – LiraNuna

+4

Phần mở rộng rõ ràng sẽ là 'Bin :: OOOO :: IIOO :: IIIO' được cho là dễ đọc hơn rất nhiều. – MSalters

3

Về mặt kỹ thuật nó không phải là C hay C++, nó là một phần mở rộng cụ GCC, nhưng GCC cho phép binary constants như đã thấy here:

The following statements are identical: 

i =  42; 
i =  0x2a; 
i =  052; 
i = 0b101010; 

Hy vọng rằng sẽ giúp. Một số trình biên dịch Intel và tôi chắc chắn những người khác, thực hiện một số phần mở rộng của GNU. Có thể bạn may mắn.

2

Một #define đơn giản hoạt động rất tốt:

#define HEX__(n) 0x##n##LU 

#define B8__(x) ((x&0x0000000FLU)?1:0)\ 
       +((x&0x000000F0LU)?2:0)\ 
       +((x&0x00000F00LU)?4:0)\ 
       +((x&0x0000F000LU)?8:0)\ 
       +((x&0x000F0000LU)?16:0)\ 
       +((x&0x00F00000LU)?32:0)\ 
       +((x&0x0F000000LU)?64:0)\ 
       +((x&0xF0000000LU)?128:0) 

#define B8(d) ((unsigned char)B8__(HEX__(d))) 
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) + B8(dlsb)) 
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) + ((unsigned long)B8(db2)<<16) + ((unsigned long)B8(db3)<<8) + B8(dlsb)) 

B8(011100111) 
B16(10011011,10011011) 
B32(10011011,10011011,10011011,10011011) 

Không phát minh của tôi, tôi thấy nó trên một diễn đàn một thời gian dài trước đây.