2010-02-12 45 views
5

我剛開始學習彙編在我的計算機科學類,我使用指定的舍入模式有一個分配給圓一個浮點值。我試圖用fstcw,fldcwfrndint來實現這個功能。我修改舍入控制位,在數字的四捨五入,然後恢復先前的控制位(賦值的一個要求)。與內聯彙編雙精度數(GCC,IA-32)工作

當前突出的問題是,指令fld %1似乎加載錯誤的值到st(0)浮點寄存器(例如,如果我叫用2.6207值的函數,數-1.9427(...)電子29被裝入寄存器)。這可能是由於gcc的內嵌asm()或別的東西被誤用,但我不確定它爲什麼會發生。

這是我有:

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; 
} 

我會很感激任何指針什麼是錯的代碼,具體涉及到fld %1線和asm輸入/輸出。 (當然,如果你能找到其他問題,也可以隨時讓我知道他們。)我不希望任何人爲我做功課,只是指出我的方向。謝謝!

+0

哇,那真是太棒了。希望我能幫忙,但是我做不到! :) – 2010-02-12 05:51:42

+0

你能告訴我們這個函數的彙編輸出嗎?並且如果代碼字節不是太麻煩的話。 – 2010-02-12 06:42:39

+0

@John:它將被組裝的代碼並不令人意外;這一切都在一個巨大的不透明(對海灣合作委員會)asm塊。 :-P然而,將它分解成許多小的彙編語句(比如我的文章)會讓gcc有更多的自由去做一些不同的事情。 – 2010-02-12 06:49:05

回答

2

至少有一個問題與當前的代碼是它使用的是單精度浮點FLD和FSTP點版本。如果你用fldl和fstpl替換它們,它可能會起作用。

+0

我查了一下。這似乎是正確的解決方案,因爲gcc使用AT&T指令並要求l操作數,所以FLDL是正確的。 – 2010-02-12 07:13:59

+0

+1是的,它似乎* l版本將工作。我發佈的代碼片段在拆解時也有* l後綴。 (顯然,就我而言,我只是選擇讓gcc通過使用約束而不是手動編寫加載/存儲指令來完成所有艱苦的工作。) – 2010-02-12 07:17:29

+0

我試圖保持問題的精神,但您的答案要好得多: ) – tyranid 2010-02-12 18:01:15

2

這是我得到的。它沒有經過測試,但希望與您一起工作的時間不會太短。 :-)

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; 
} 

雖然,如果你不使用匯編實現自己的舍入模式要求,想想<fenv.h>使用函數來代替。 :-)

+0

我需要使用匯編:) – jtbandes 2010-02-12 06:48:14

+0

@jtbandes:很酷。在這種情況下,請隨時測試我的版本,並讓我知道需要修復的問題。 :-) – 2010-02-12 06:49:55

+0

'+ t'約束是如何工作的?在找到其他人的位置時我找不到關於它的信息。 – jtbandes 2010-02-12 15:35:36

0

作爲符號變化,則意味着符號位(這是最顯著,第一個)是不正確的。 這對我來說,指針%1錯誤地對齊。如果你有一個字節,它可以 開始在0,1,2 ......但如果你訪問兩個字節,地址必須是0,2,4 ....和雙地址的情況下 必須是偶數可分8:0,8,16

所以檢查您所使用的加載值的地址是由8整除大會對齊關鍵字來保證您的數據正確對齊。

+1

x86不需要這種對齊方式,但僅對於性能而言是明智的。 – 2010-02-12 06:52:52