Renesas Synergy™

FAQ 105952 : C言語で乗算式を記述したとき、結果が期待した値になりません。

Q: 質問

C言語で乗算式を記述したとき、結果が期待した値になりません。なぜですか?例えば以下の例で、期待した値(y0の値)は0x0300ですが、実際には0x055となります。


A: 回答

y0の値が0x0300とならないのは、乗算の結果は"int"で保持されるため乗算時にオーバーフローするためです。x0を "unsigned long" でキャストして乗算結果をlongで保持するようにしてください。

これにより、y0の値が0x0300となります。

#define CONST_A    0x0400
#define CONST_B    0x0c0

void main( void )
{
unsigned char    x0;
unsigned int       y0;

    x0 = 0x090;
    y0 = ( (unsigned long)x0 * CONST_A ) / CONST_B;
}


[参考] x0が"unsigned char"のとき、y0が0x055になる原因は以下の通りです。

  1. "y0 = ( x0 * CONST_A ) / CONST_B;" の式において、"x0 * CONST_A" を実行する際にx0は "singned int" に型変換されます。乗算の結果は "int" です。
    ※即値(CONST_A,CONST_B)は、"signed int"で扱います。
  2. 乗算の結果をCONST_Bで除算するとき、M16Cのニーモニックの制限によって、被除数 (上記1.で示した乗算結果) を32ビットに符号拡張します。
    ※M16Cには、32ビットを16ビットで除算するニーモニックしかありません。
  3. 2.の除算結果をy0に格納します。
    この手順の1.で、unsigned char * singed intの結果はintで扱いますが、乗算の結果は0x024000で上位1バイト(0x020000)が捨てられます。このため、除算は"0x4000/0x0c0"となり、結果0x055となります。

    "y0 = ( x0 * CONST_A ) / CONST_B;" の出力コードは以下の通り。
    mov.b    -2[FB],A0              ; x0
    mov.w    A0,R0
    mul.w     #03ffH,R0
    exts.w    R0
    div.w      #00c8H
    mov.w    R0,-2[FB]      ; y0

    "y0 = ( (unsigned long)x0 * CONST_A ) / CONST_B;" の出力コードは以下の通り。
    mov.b     -2[FB],R0L       ; x0
    mov.b     #00H,R0H
    mulu.w    #03ffH,R0
    push.w   #0000H
    push.w   #00c8H
    .glb        __i4div
    jsr.a       __i4div
    add.b     #4H,SP
    mov.w     R0,-2[FB]        ; y0

 

適用製品

M16Cシリーズ,R8Cファミリ用C/C++コンパイラパッケージ [M3T-NC30WA]

他にご質問がございましたら、リクエストを送信してください