2010-06-11 10 views
8

Birisi bana 32 bit kayan nokta değerini 16 bit kayan nokta değerine nasıl dönüştürdüğümü açıklayabilir mi?Float32 to Float16

(s = işareti e = üs ve m = mantis)

32 bit şamandıra 1s7e24m
ve 16 bit şamandıra ise O 1s5e10m

olan bu durumu kadar basittir?

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

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

Bu kadar basit olmadığımı farz ediyorum ... bu yüzden bana ne yapman gerektiğini söyleyen var mı?

Düzenleme: Görüyorum ki, üçüncü tarafımın hatalı geçişini yaptım ... bu yüzden daha iyi olur mu?

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

Bunun doğru olduğunu umuyorum. Özür dileyen bir şey eksik olsaydım özür dilerim. Bir Cuma gecesi neredeyse gece yarısı ... bu yüzden "tamamen" ayık değilim;)

Düzenleme 2: Ooops. Yine tetikledi. En alttaki 3 biti kaybetmek istiyorum! Peki bu konuda:

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

Final kod olmalıdır:

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

Bence bu zaten sorulmuştu (ve cevaplandırıldı): http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion – humbagumba

+0

bu kadar basit olabilir, ama float32, tüm "hassas" ı kullanmadığı sürece hassaslığı kaybedersiniz ... temel olarak, 5/7 exp'in (en anlamlı olanları alırsınız) ve mantislerin 10/24'ünü alırsınız; Bu oranlar, dönüşümde ne kadar kaybedebileceğinizi söyler. Tam olarak, 16 bit tamsayıya 32 bit tamsayıya sığdırmak istediğinizde gerçekleşir ... rappresentable sayı aralığı daha küçüktür; mantissa "kesme", "hassas" azaltır ve üssü de aralığı sınırlar: 5 işaretli bit -16 ila +15, -64/+ 63 karşı (eğer doğru yaptıysam ...: D geç olduğunu) – ShinTakezou

+0

@ShinTakezou: Kesinlikle veri 16-bit kaybetmek ve hassas değil kaybetmek mümkün değil mi ?? Float16 çok daha az hassastır ve bu nedenle otomatik olarak daha az hassasiyete sahiptir ... ya da sizi yanlış anlamış mıyım? – Goz

cevap

4

üsler sizin float32 ve float16 gösterimleri muhtemelen önyargılı ve yanlı farklı bulunmaktadır. Float32 sunumundan aldığınız üssü, gerçek üssü almak ve daha sonra float16 gösterimi için önyargısızlaştırmanız gerekir.

Bu ayrıntıdan başka, bunun kadar basit olduğunu düşünüyorum, ancak zaman zaman kayan noktalı temsillerle şaşırıyorum.

DÜZENLEME: taşma için

  1. Kontrol sen bunu yaparken üstellerle şeyi yapıyor.

  2. Algoritmanınız mantisa ait son bitleri biraz aniden keser, bu kabul edilebilir olabilir, ancak atılmak üzere olan bitlere bakılarak, en yakına en yakını uygulamak isteyebilirsiniz. "0 ..." -> aşağı yuvarla, "100.,001 ..." -> yukarı, "100.,00" -> yuvarlak bile.

+0

IEEE754 Standardında 32 bit kayan nokta sayısı 23 bit mantis ve 8 bit üssü içerir. – bbudge

+0

@bbudge ... Yeterince adil bellekten yapmaya çalışıyordum. Yanlış bir şekilde yanlış yönlendirdim;) – Goz

4

üs, tarafsız kısılmış ve rebiased olması gerekiyor. Bu kullandığım hızlı kodudur: Bu kod da hızlı üs için bir tabloda olacak

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; 

, ancak kolayca bir SIMD iş akışına uyarlanmıştır çünkü bu birini kullanın.uygulama

Sınırlamalar: tanımsız değerler verecektir float16 temsil edilemez

  • Taşan değerler.
  • Altta kalan değerler, sıfır yerine 2^-15 ve 2^-14 arasında tanımsız bir değer döndürür.
  • Denormals tanımsız değerler verecektir.

Denormals'a dikkat edin. Mimariniz bunları kullanıyorsa, programınızı büyük ölçüde yavaşlatabilir.