C, C++, Java에서는 부동 소수점(float) 수를 대상으로 다양한 수학 연산을 수행합니다. 이번 글에서는 부동 소수점 수가 결합 법칙(associativity rule)을 따르는지 직접 확인해 보겠습니다.
결론부터 말하면 아니요. 부동 소수점 수는 특정한 경우에 결합 법칙을 따르지 않습니다. 아래 예제 코드를 통해 그 이유를 살펴보겠습니다.
예제 코드
#include<iostream>
using namespace std;
main() {
float x = -500000000;
float y = 500000000;
float z = 1;
cout << "x + (y + z) is: " << x + (y + z) << endl;
cout << "(x + y) + z is "<< (x + y) + z << endl;
}
실행 결과
x + (y + z) is: 0 (x + y) + z is 1
실행 결과를 보면 두 표현식의 출력값이 서로 다른 것을 확인할 수 있습니다. 하지만 일반적인 수학적 관점에서 보면 두 식 모두 항상 1이 되어야 한다고 생각할 수 있습니다. 그렇다면 왜 이런 차이가 발생하는 것일까요?
첫 번째 표현식 x + (y + z)에서는 괄호 안의 (500000000 + 1)이 먼저 계산됩니다. 그러나 부동 소수점의 유효 자릿수 제한으로 인해 반올림(round-off) 오차가 발생하고, 이 값은 다시 500000000으로 처리됩니다. 여기에 -500000000을 더하면 최종 결과는 0이 됩니다.
반면 두 번째 표현식 (x + y) + z에서는 (-500000000 + 500000000)이 먼저 계산되어 0이 되고, 이후에 1을 더하므로 최종 결과는 1이 됩니다.
만약 같은 연산을 정수형(int)으로 수행했다면 정밀도 손실이 없기 때문에 두 표현식 모두 동일한 결과인 1을 반환합니다.
이처럼 부동 소수점 연산에서는 피연산자의 순서와 결합 방식에 따라 결과가 달라질 수 있으므로, 높은 정밀도가 필요한 프로그램에서는 double 타입 사용이나 연산 순서 조정 등을 신중하게 고려해야 합니다.