2010-02-12 20 views
5

Bilgisayar bilimi sınıfımda derleme öğrenmeye yeni başlıyorum ve belirli bir yuvarlama modunu kullanarak kayan nokta değerini yuvarlamak için bir atamam var . Bunu fstcw, fldcw ve frndint kullanarak uygulamaya çalıştım. Yuvarlama kontrol bitlerini değiştiriyorum, sayıyı yuvarlayın ve önceki kontrol bitlerini (atama gereksinimi) geri yükleyin.Satır içi derlemede (GCC, IA-32) çift kesinlikli sayılarla çalışma

Geçerli önemli sorun, fld %1 yönergesinin st(0) kayan nokta kaydına yanlış değer yüklediği anlaşılıyor (örneğin, işlevi 2.6207 değeriyle çağırırsam, sayı -1.9427 (...) e-29 kayıtlara yüklenir). Bu, gcc satır içi asm()'un yanlış kullanımından veya başka bir nedenden dolayı olabilir, ancak bunun neden olduğundan emin değilim.

İşte ne var:

double roundD (double n, RoundingMode roundingMode) 
{ 
    // control word storage (2 bytes for previous, 2 for current) 
    char *cw = malloc(4*sizeof(char)); 
    char *cw2 = cw + 2; 

    asm("fstcw %3;" // store control word in cw 
     "mov %3,%4;" // copy control word into cw2 
     "and $0xF3FF,%4;" // zero out rounding control bits 
     "or %2,%4;" // put new mode into rounding control bits 
     "fldcw %5;" // load the modified control word 
     "fld %1;" // load n into st(0) 
     "frndint;" // round n 
     "fstp %0;" // load st(0) back into n 
     "fldcw %3;" // load the old control word from cw 
     : "=m" (n) 
     : "m" (n), "m" (roundingMode), 
      "m" (cw), "r" (cw2), "m" (cw2) // mov requires one argument in a register 
     ); 

    free(cw); 

    return n; 
} 

Özellikle fld %1 hat ve asm girişlerine/çıkışlar ile ilgili, bu kodu nesi herhangi işaretçiler takdir ediyorum. (Elbette, başka problemler bulabilirseniz, onları da bana bildirmekten çekinmeyin.) Kimsenin benim için ödevimi yapmasını istemiyorum, sadece doğru yöne doğrult. Teşekkürler!

+0

Vay, bu oldukça badass. Keşke yardımcı olabilirdim ama yapamam! :) –

+0

bize bu işlevin montaj çıktısını gösterebilir misin? ve kod baytları da çok fazla sorun değil. –

+0

@John: Montajı yapılacak kod sürpriz değil; hepsi bir dev opak (gcc) asm bloğunda. :-P Birçok küçük asm deyimine (postum gibi) bölünürken, gcc daha farklı bir şey yapmak için daha fazla enlem verir. –

cevap

2

Geçerli kodunuzla ilgili en az bir sorun, fld ve fstp'nin tek kesinlikli kayan noktalı sürümlerini kullanmaktır. Bunları fldl ve fstpl ile değiştirirseniz muhtemelen işe yarayacaktır.

+0

Ben baktım. Bu doğru çözüm gibi görünüyor çünkü gcc AT & T komutlarını kullanıyor ve l işlenenini talep ediyor, bu yüzden FLDL haklı. –

+0

+1 Evet, * l sürümleri çalışacak gibi görünüyor. Göndermiş olduğum pasaj, * l son ekine de sahip. (Açıkçası, benim durumumda gcc'nin tüm zorlu işleri, yük/mağaza talimatlarını manuel olarak kodlamaktan ziyade kısıtlamalar kullanarak yapmasını tercih ettim.) –

+0

Sorunun ruhunu korumayı denedim ama cevabınız çok daha iyiydi:) – tyranid

2

İşte sahip olduğum şey. Test edilmedi, ama umarım sizinle çalışmak için daha az gland olur. :-) Eğer yuvarlama modunu elde etmek takımını kullanmak için gerekli değilseniz, bunun yerine <fenv.h> içinde işlevlerini kullanma hakkında

double 
roundd(double n, short mode) 
{ 
    short cw, newcw; 

    __asm__("fstcw %w0" : "=m" (cw)); 
    newcw = cw & 0xf3ff | mode; 
    __asm__("fldcw %w0" : : "m" (newcw)); 
    __asm__("frndint" : "+t" (n)); 
    __asm__("fldcw %w0" : : "m" (cw)); 
    return n; 
} 

düşünmek rağmen. :-)

+0

Montajı kullanmam gerekiyor :) – jtbandes

+0

@jtbandes: Cool. Bu durumda, sürümümü test etmekten çekinmeyin ve neyin düzeltilmesi gerektiğini bana bildirin. :-) –

+0

'+ t' kısıtlaması nasıl çalışır? Diğerlerini bulduğum yer hakkında bilgi bulamıyorum. – jtbandes

0

İşaret değiştikçe, işaret bitinin (ki en önemlisi, ilk olan) doğru olmadığı anlamına gelir. Bu bana% 1 işaretçisinin yanlış hizalandığını varsayalım. Eğer bir baytınız varsa, 0,1,2'den başlayabilir ... ama iki bayta erişirseniz, adres 0,2,4 .... olmalıdır ve çiftin olması durumunda adresin bile olması gerekir. 8: 0,8,16

Böylelikle değeri yüklemek için kullandığınız adresin 8'e bölünüp bölünmediğini kontrol edin. Montaj verilerinizin doğru bir şekilde hizalanmasını garanti etmek için align anahtar sözcüğüne sahiptir.

+1

Bu hizalama x86 tarafından gerekli değil, yalnızca performans için önerilir. –