2012-05-02 32 views
5

Có, tôi nhận thức được tiêu chuẩn về độ chính xác một nửa của IEEE-754, và có tôi biết về công việc được thực hiện trong lĩnh vực này. Đặt rất đơn giản, tôi đang cố gắng để tiết kiệm một số điểm nổi đơn giản (như 52.1, hoặc 1.25) chỉ trong 2 byte.Làm cách nào để lưu số dấu phẩy động trong 2 byte?

Tôi đã thử một số triển khai trong Java và trong C# nhưng chúng làm hỏng giá trị đầu vào bằng cách giải mã một số khác. Bạn cấp dữ liệu trong 32.1 và sau khi mã hóa giải mã, bạn nhận được 32.0985.

Có cách nào tôi có thể lưu trữ số dấu phẩy động chỉ trong 16 bit mà không làm hỏng giá trị đầu vào không?

Cảm ơn rất nhiều.

+5

Điểm nổi không thể mã hóa '32.1' – CodesInChaos

+2

Bạn cần mã hóa các số nào và có bao nhiêu chữ số có nghĩa? Xem xét các số thập phân cố định hoặc dấu phẩy động. – CodesInChaos

+0

Bạn có thể lưu trữ nó như là một 'unsigned short', với một số bit được sử dụng cho một phần mũ? Sau đó, bạn sẽ tự chuyển đổi từ định dạng này sang độ chính xác đơn lẻ 'float'. – Matthew

Trả lời

5

Bạn có thể lưu trữ ba chữ số trong BCD và sử dụng bốn bit còn lại cho vị trí dấu thập phân:

52.1 = 521 * 10^-1 => 0x1521 
1.25 = 125 * 10^-2 => 0x2125 

này sẽ cung cấp cho bạn một loạt ,0000000000000001-999.Bạn có thể tất nhiên thêm một bù đắp cho điểm thập phân để có được ví dụ phạm vi 0,0000000001 để 999000000.


đơn giản thực hiện bốn bit được sử dụng cho vị trí dấu thập phân, và phần còn lại cho giá trị. Không kiểm tra lỗi, và không kiểm tra kỹ lưỡng. (Có thể có những vấn đề chính xác với một số giá trị khi sử dụng != để so sánh đôi.)

public static short Encode(double value) { 
    int cnt = 0; 
    while (value != Math.Floor(value)) { 
    value *= 10.0; 
    cnt++; 
    } 
    return (short)((cnt << 12) + (int)value); 
} 

public static double Decode(short value) { 
    int cnt = value >> 12; 
    double result = value & 0xfff; 
    while (cnt > 0) { 
    result /= 10.0; 
    cnt--; 
    } 
    return result; 
} 

Ví dụ:

Console.WriteLine(Encode(52.1)); 
Console.WriteLine(Decode(4617)); 

Output:

4617 
52.1 
+0

@Geotarget: Bạn có thể ép 4 chữ số thành hai byte, nhưng sau đó bạn chỉ còn lại hai bit để mô tả vị trí dấu thập phân. Đối với các số có ít chữ số bạn chỉ cần điền bằng số không, nghĩa là '1,5' giống với số '001.5' hoặc' 1.500'. – Guffa

+0

Bạn có thể hiển thị các ví dụ về float cho các chức năng mã hóa/giải mã nhị phân không? Tôi xin lỗi nhưng tôi không thực sự hiểu những gì đang hapenning. –

+0

@Geotarget: Tôi đã thêm một triển khai đơn giản ở trên. – Guffa

3

Vấn đề là bạn không thể đại diện chính xác 32.1 trong bất kỳ loại dấu phẩy động nhị phân nào.

Trong độ chính xác đơn, giá trị thể hiện gần nhất là 32.099998. Trong một nửa độ chính xác, nó rõ ràng là 32.0985.

Bạn có thể xem xét loại dấu phẩy động thập phân, nhưng giải pháp này không phải là duy nhất với độ chính xác một nửa.

+0

Giá trị nửa độ chính xác sử dụng 11 bit cho significand (bit đầu tiên 1 là ẩn). Trong khoảng [32,64], 6 trong số các bit đó được sử dụng cho phần nguyên, để lại 5 bit cho phần phân số. Vì vậy, trong miền đó, [32,64], các giá trị thể hiện được chính xác là mulitples của 1/(2 ** 5) = 1/32. Giá trị gần nhất với '32.1' sẽ là 32 + 3/32 (a.k.a. 1027/32) là' 32.09375'. Vì vậy, "rõ ràng" của bạn là không chính xác, sau khi tất cả. Tôi không biết người hỏi có ví dụ của anh ta từ đâu. Đối với một giá trị nửa độ chính xác, thông thường bạn sẽ chỉ xuất ra 3 chữ số thập phân, do đó, "32.1" sẽ là độ chính xác thông thường. –

1

Từ ví dụ của bạn, bạn muốn lưu 3 chữ số và dấu thập phân. Bạn có thể chỉ cần mã hóa 'bảng chữ cái' của 11 biểu tượng thành mã 4 bit và lưu trữ 4 x 4 bit trong 2 byte.

Tôi đặt cược bạn ngay bây giờ 'giải thích' rằng yêu cầu của bạn không thỏa mãn bằng cách tiếp cận này!

+0

vâng, một cái gì đó giống như thập phân mã nhị phân sẽ hoạt động tốt – Kell

6

C# không có chức năng tích hợp cho điều đó, nhưng bạn có thể thử phương pháp tiếp cận điểm cố định.

Ví dụ về 8,8 điểm cố định (8 trước dấu phẩy, 8 sau):

float value = 123.45; 
ushort fixedIntValue = (ushort)(value * 256); 

Bằng cách này, các số được lưu trữ như thế này: XXXXXXXX, XXXXXXXX

và bạn có thể lấy lại nổi một lần nữa sử dụng này:

float value = fixedIntValue/256f; 
+1

Điều đó cũng có độ chính xác giới hạn. 52,1 trở thành 52.09765625. – Guffa

+0

Vâng, bạn không thể có mọi thứ. Nếu bạn muốn nhiều hơn, bạn có thể thử 6,10 điểm cố định hoặc sử dụng 4 byte. – bytecode77

+1

Các op không yêu cầu tất cả mọi thứ, chỉ để lấy lại chính xác cùng một giá trị. Điều này hoàn toàn không hợp lý, nếu phạm vi giới hạn có thể chấp nhận được. Bạn chỉ cần sử dụng một cách tiếp cận khác với một số nhị phân nổi/cố định. – Guffa

5

bạn có chắc chắn bạn cần một vi-tối ưu hóa như vậy, so với chỉ đơn giản là sử dụng một float hoặc double?

Bạn sẽ được phục vụ tốt hơn bằng cách lưu trữ short và hiểu rằng, ví dụ: chia cho 100 để tạo số thực? (Ví dụ: các ví dụ về 52.1 và 1.25 của bạn có thể được lưu trữ là 5210 và 125) Tôi nghĩ đây có thể là giải pháp tốt nhất cho bạn.

Nếu bạn được thiết lập sử dụng số dấu phẩy động thực tế, bạn có thể lấy số đã giải mã và làm tròn số x chữ số có nghĩa, (từ ví dụ của bạn, 3). với (lưu ý rằng có, đó là cố ý mơ hồ - bạn không thể đảm bảo nhận được bản gốc trừ khi bạn lưu trữ bản gốc).

2

Có 4278190080 32-bit floating-point giá trị, không bao gồm NaN và infinities. Có 65.536 giá trị cho 16 bit trong hai byte. Rõ ràng, không thể mã hóa duy nhất tất cả các giá trị dấu phẩy động trong hai byte.

Bạn muốn mã hóa mã nào?

Ngay cả đối với một giá trị của dấu và số mũ (ví dụ: tất cả các giá trị dấu phẩy động từ 4 đến 8, không bao gồm 8), có 8.388.608 giá trị dấu phẩy động, vì vậy bạn thậm chí không thể mã hóa các giá trị đó thành hai byte.

Bạn phải giới hạn bản thân với một tập con nhỏ các giá trị để mã hóa. Một khi bạn đã làm điều đó, mọi người có thể có những gợi ý về cách mã hóa chúng. Vấn đề thực tế bạn đang cố gắng giải quyết là gì?

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