2010-06-11 24 views
8

Ai đó có thể giải thích cho tôi cách tôi chuyển đổi giá trị dấu phẩy động 32 bit sang giá trị dấu phẩy động 16 bit không?Float32 to Float16

(s = dấu hiệu e = số mũ và m = mantissa)

Nếu 32-bit float là 1s7e24m
Và 16-bit float là 1s5e10m

Sau đó là nó đơn giản như đang làm gì?

int  fltInt32; 
short fltInt16; 
memcpy(&fltInt32, &flt, sizeof(float)); 

fltInt16 = (fltInt32 & 0x00FFFFFF) >> 14; 
fltInt16 |= ((fltInt32 & 0x7f000000) >> 26) << 10; 
fltInt16 |= ((fltInt32 & 0x80000000) >> 16); 

Tôi giả định nó KHÔNG đơn giản như vậy ... để bất cứ ai có thể cho tôi biết bạn cần làm gì?

Chỉnh sửa: Tôi cam thấy tôi đã thay đổi số mũ sai của mình ... vì vậy điều này có tốt hơn không?

fltInt16 = (fltInt32 & 0x007FFFFF) >> 13; 
fltInt16 |= (fltInt32 & 0x7c000000) >> 13; 
fltInt16 |= (fltInt32 & 0x80000000) >> 16; 

Tôi hy vọng điều này là chính xác. Xin lỗi nếu tôi thiếu một cái gì đó hiển nhiên đã được nói. Gần nửa đêm của nó vào một đêm thứ sáu ... vì vậy tôi không "hoàn toàn" tỉnh táo;)

Chỉnh sửa 2: Rất tiếc. Buggered nó một lần nữa. Tôi muốn mất 3 bit hàng đầu chứ không phải thấp hơn! Vậy làm thế nào về điều này:

fltInt16 = (fltInt32 & 0x007FFFFF) >> 13; 
fltInt16 |= (fltInt32 & 0x0f800000) >> 13; 
fltInt16 |= (fltInt32 & 0x80000000) >> 16; 

mã cuối cùng nên:

fltInt16 = ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13); 
fltInt16 |= ((fltInt32 & 0x80000000) >> 16); 
+2

Tôi nghĩ rằng điều này đã được yêu cầu (và được trả lời) tại đây: http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion – humbagumba

+0

nó có thể đơn giản, nhưng bạn mất độ chính xác trừ phi float32 không sử dụng tất cả "độ chính xác" mà nó có ... về cơ bản, bạn nhận được 5/7 số bit của điểm kinh nghiệm (bạn dĩ nhiên là những cái có ý nghĩa nhất), và 10/24 của mantissa; các tỷ lệ này nói một cách nào đó bạn có thể mất bao nhiêu trong chuyển đổi. chính xác như nó xảy ra nếu bạn muốn phù hợp với 32 bit số nguyên thành một số nguyên 16bits ... phạm vi số rappresentable nhỏ hơn; "cắt" mantissa làm giảm "độ chính xác", và số mũ cũng giới hạn phạm vi: 5 bit đã ký cho -16 đến +15, so với -64/+ 63 (nếu tôi đã làm đúng ...: D muộn nó là) – ShinTakezou

+0

@ShinTakezou: Chắc chắn không thể mất 16 bit dữ liệu và KHÔNG mất độ chính xác ?? Float16 là ít chính xác hơn và do đó tự động có độ chính xác ít hơn ... hoặc tôi hiểu lầm bạn? – Goz

Trả lời

4

Các số mũ trong float32 của bạn và float16 cơ quan đại diện có lẽ là thiên vị, và thiên vị khác nhau. Bạn cần phải unbias số mũ bạn nhận được từ đại diện float32 để có được số mũ thực tế, và sau đó để thiên vị nó cho đại diện float16.

Ngoài chi tiết này, tôi nghĩ nó đơn giản như vậy, nhưng tôi vẫn cảm thấy ngạc nhiên bởi các đại diện điểm nổi theo thời gian.

EDIT:

  1. Kiểm tra tràn bộ nhớ khi làm điều với số mũ trong khi bạn đang ở đó.

  2. Thuật toán của bạn cắt ngắn các bit cuối cùng của mantisa một cách đột ngột, có thể chấp nhận được nhưng bạn có thể muốn thực hiện, nói vòng tròn gần nhất bằng cách nhìn vào các bit sắp bị loại bỏ. "0 ..." -> làm tròn xuống, "100..001 ..." -> tròn lên, "100..00" -> làm tròn thành thậm chí.

+0

Số dấu phẩy động 32 bit trong tiêu chuẩn IEEE754 có 23 bit số mũ và số mũ 8 bit. – bbudge

+0

@bbudge ... công bằng đủ Tôi đã cố gắng để làm điều đó từ bộ nhớ. Tôi đã lấy sai một chút, rõ ràng;) – Goz

4

Số mũ cần phải được thiên vị, kẹp và rebiased. Đây là mã nhanh tôi sử dụng:

unsigned int fltInt32; 
unsigned short fltInt16; 

fltInt16 = (fltInt32 >> 31) << 5; 
unsigned short tmp = (fltInt32 >> 23) & 0xff; 
tmp = (tmp - 0x70) & ((unsigned int)((int)(0x70 - tmp) >> 4) >> 27); 
fltInt16 = (fltInt16 | tmp) << 10; 
fltInt16 |= (fltInt32 >> 13) & 0x3ff; 

Mã này sẽ còn nhanh hơn với bảng tra cứu số mũ, nhưng tôi sử dụng mã này vì nó dễ dàng thích nghi với quy trình làm việc SIMD.

Hạn chế của việc thực hiện:

  • giá trị tràn mà không thể được đại diện trong float16 sẽ cung cấp cho các giá trị không xác định.
  • Giá trị thiếu sẽ trả lại giá trị không xác định giữa 2^-152^-14 thay vì bằng không.
  • Các biến thể sẽ cung cấp các giá trị không xác định.

Hãy cẩn thận với các biến thể. Nếu kiến ​​trúc của bạn sử dụng chúng, chúng có thể làm chậm chương trình của bạn rất nhiều.