【C言語】
絶対値を求めるabs(整数)とfabs(浮動小数点)

warning: using integer absolute value function ‘abs’ when argument is of floating-point type ‘double’

警告:
引数が浮動小数点型 ‘double’ であるのに
引数が整数の絶対値関数 ‘abs’ を使用している。
[-Wabsolute-value]

■この記事の概要

この記事では、C言語で整数の絶対値を求めるabs関数と浮動小数点用のfabs関数の違いや使用時の注意点が詳しく解説されています。#includeの要件や未定義動作への対応方法も紹介しています。

■整数の絶対値を求めるabs関数

#include <stdio.h>
//abs関数使用時必要
#include <stdlib.h>

int main(void){
    int x = -1234;
    printf("整数の絶対値 %d->%d\n",
        x,
        abs(x)
    );
}

引数が整数の時は
abs()関数を使用してください。

abs()を使う時は
#include <stdlib.h>を忘れないでください。

■浮動小数点の時abs関数は使えない

#include <stdio.h>
#include <stdlib.h>

int main(void){
    double x = -12.34;
    printf("浮動小数点の絶対値?? %f->%d\n",
        x,
        abs(x)  //ダメ
    );
}

引数が浮動小数点の場合abs()は使えません。

■浮動小数点の絶対値を求めるfabs関数

#include <stdio.h>
//数学関数ヘッダが必要
#include <math.h>
//コンパイル環境によって -lm が必要
//gcc  f3.c -fno-builtin -lm

int main(void){
    double x = -12.34;
    printf("浮動小数点の絶対値 %f->%f\n",
        x,
        fabs(x) //良い
    );
}

引数が浮動小数点の場合abs()ではなくて、
適切な関数fasb()を使用してください。

fabs()を使う時は
(1)#include <math.h>を忘れないでください。
(2)コンパイル環境によっては数学関数ライブラリをリンクするため-lm オプションが必要です。

■狭い型を絶対値化する時の注意

#include <stdio.h>
#include <stdlib.h>

int main(void){
    signed char x = -128 ;
    if(x < 0){
        x = -x;
        printf("負値のまま %d\n",x);
    }
    
    signed char y = -128 ;
    if(y < 0){
        y = abs(y);
        printf("負値のまま %d\n",y);
    }

    signed char z = -128 ;
    printf("期待した結果 %d\n",abs(z));
}

signed char の
最大値は 127
最小値は -128
なので
signed char で -(-128)=128は表現できません。


■abs(INT_MIN)に注意

runtime error: negation of -2147483648 cannot be represented in type ‘int’; cast to an unsigned type to negate this value to itself

警告:最大の負整数の絶対値は、定義されていない。
[-fsanitize=undefined]

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
//gcc -fsanitize=undefined
int main(void){
    int     x = INT_MIN ;
    if(x < 0){
        x = -x;
        printf("負値のまま %d\n",x);
    }
    
    printf("負値のまま %d ➡ %d\n",
        INT_MIN,
        abs(INT_MIN)   //絶対値にならない 
    );
}

(1) abs(INT_MIN)の動作はマニュアルによると決まっていないそうです。(未定義の動作?)
gccの場合
INT_MAX= 2147483647
INT_MIN=-2147483648
なので INT_MIN の絶対値 2147483648 はint で表現できないため。

(2) -INT_MINの計算は未定義の動作となり、
gcc -fsanitize=undefined (未定義動作検出オプション)でコンパイルし走らせると
x=-xで異常終了します。