좋아하는 프로그래밍 언어로 1에서 2,000,000까지의 모든 숫자를 합한 적이 있습니까? 결과는 수동으로 쉽게 계산할 수 있습니다 (2,000,001,000,000). 부호없는 32 비트 정수의 최대 값보다 약 900 배 더 큽니다.
C #이 출력됩니다 -1453759936
-음수! 그리고 Java도 마찬가지입니다.
이는 기본적으로 산술 오버플로를 무시하는 일반적인 프로그래밍 언어가 있음을 의미합니다 (C #에는이를 변경할 수있는 숨겨진 옵션이 있음). 그것은 나에게 매우 위험한 행동이며 그러한 오버플로로 인한 Ariane 5의 충돌이 아니 었습니까?
그렇다면 위험한 행동의 배후에있는 디자인 결정은 무엇입니까?
편집하다:
이 질문에 대한 첫 번째 답변은 과도한 검사 비용을 나타냅니다. 이 가정을 테스트하기 위해 짧은 C # 프로그램을 실행 해 보겠습니다.
Stopwatch watch = Stopwatch.StartNew();
checked
{
for (int i = 0; i < 200000; i++)
{
int sum = 0;
for (int j = 1; j < 50000; j++)
{
sum += j;
}
}
}
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
내 컴퓨터에서 확인 된 버전은 11015ms, 확인되지 않은 버전은 4125ms가 걸립니다. 즉, 확인 단계는 숫자를 추가하는 데 거의 두 배가 걸립니다 (총 시간의 원래 시간의 3 배). 그러나 10,000,000,000 회의 반복으로 점검에 걸리는 시간은 여전히 1 나노초 미만입니다. 중요한 상황이있을 수 있지만 대부분의 응용 프로그램에서는 중요하지 않습니다.
편집 2 :
서버 응용 프로그램 (여러 센서에서받은 데이터를 분석하는 Windows 서비스, 상당히 많은 수의 크 런칭)을 /p:CheckForOverflowUnderflow="false"
매개 변수 (일반적으로 오버플로 검사를 켭니다)로 다시 컴파일 하여 장치에 배포했습니다. Nagios 모니터링에 따르면 평균 CPU로드는 17 %로 유지되었습니다.
이것은 위의 예제에서 찾은 성능 적중이 우리의 응용 프로그램과 전혀 관련이 없음을 의미합니다.
(1..2_000_000).sum #=> 2000001000000
. 내가 가장 좋아하는 언어 중 하나 : sum [1 .. 2000000] --=> 2000001000000
. 내가 좋아하는 것이 아닙니다 : Array.from({length: 2000001}, (v, k) => k).reduce((acc, el) => acc + el) //=> 2000001000000
. (공평하게, 마지막 것은 부정 행위입니다.)
Integer
Haskell의 @BernhardHiller 는 임의 정밀도이며 할당 가능한 RAM이 부족하지 않는 한 숫자를 보유합니다.
But with the 10,000,000,000 repetitions, the time taken by a check is still less than 1 nanosecond.
그것은 루프가 최적화되었음을 나타냅니다. 또한 그 문장은 나에게 매우 유효한 이전 숫자와 모순됩니다.
checked { }
섹션을 사용 하여 산술 오버플로 검사를 수행해야하는 코드 부분을 표시 할 수 있습니다 . 이것은 성능 때문입니다