for 루프에서 과학적 표기법 사용
최근에 형태의 루프가있는 코드를 발견했습니다.
for (int i = 0; i < 1e7; i++){
}
나는 1e7이 부동 소수점 유형이기 때문에 이것을 수행하는 지혜에 의문을 제기하고 i
중지 조건을 평가할 때 승격시킬 것입니다. 이것이 우려의 원인이되어야합니까?
여기 방 코끼리 의 범위이다 int
수 작게 -32767 같은 +32767까지, 그리고 이러한 방법이보다 큰 값을 할당에 문제가 int
되는 미정 .
그러나 요점은 매우 나쁜 습관 이기 때문에 실제로 당신을 염려해야합니다 . 예, 1e7은 부동 소수점 double 유형입니다.
i
유형 승격 규칙으로 인해 부동 소수점으로 변환 될 것이라는 사실 은 다소 논란의 여지가 있습니다. 명백한 정수 리터럴 이 예기치 않게 잘리는 경우 실제 피해가 발생합니다 . "예를 통한 증명"을 통해 먼저 루프를 고려하십시오.
for (std::uint64_t i = std::numeric_limits<std::uint64_t>::max() - 1024; i ++< 18446744073709551615ULL; ){
std::cout << i << "\n";
}
이것은 i
예상대로 범위 의 모든 연속 값을 출력합니다 . 는 2의 64 제곱보다 1이 적다는 점 std::numeric_limits<std::uint64_t>::max()
에 유의하십시오 18446744073709551615ULL
. (여기서는 유형 ++<
작업시 유용한 슬라이드 형 "연산자" 를 사용하고 unsigned
있습니다. 많은 사람들이 생각 -->
하고 ++<
난독 화하는 것으로 간주 하지만 과학 프로그래밍에서는 일반적입니다. 특히 -->
.)
이제 내 컴퓨터에서 double은 IEEE754 64 비트 부동 소수점입니다. (예 : 체계는 2의 거듭 제곱을 정확하게 표현하는 데 특히 좋습니다. IEEE754는 2의 거듭 제곱을 1022까지 정확하게 표현할 수 있습니다.) 따라서 18,446,744,073,709,551,616
(2의 64 제곱)은 정확히 double로 표현할 수 있습니다. 그 전에 가장 가까운 표현 가능한 숫자 18,446,744,073,709,550,592
는 1024보다 적습니다.
이제 루프를 다음과 같이 작성하겠습니다.
for (std::uint64_t i = std::numeric_limits<std::uint64_t>::max() - 1024; i ++< 1.8446744073709551615e19; ){
std::cout << i << "\n";
}
내 컴퓨터 에서 : (이미 본 숫자) 의 하나의 값만 출력 합니다. 이것은 그것이 부동 소수점 유형 임을 증명합니다 . 컴파일러가 리터럴을 정수 유형으로 처리하도록 허용 된 경우 두 루프의 출력은 동일합니다.i
18,446,744,073,709,550,592
1.8446744073709551615e19
int
32 비트 이상 이라고 가정하면 작동합니다 .
그러나 정말로 지수 표기법을 사용하려면 루프 외부에 정수 상수를 정의하고 다음과 같이 적절한 캐스팅을 사용해야합니다.
const int MAX_INDEX = static_cast<int>(1.0e7);
...
for (int i = 0; i < MAX_INDEX; i++) {
...
}
이것을 고려하면 글을 쓰는 것이 훨씬 낫다고 말하고 싶습니다
const int MAX_INDEX = 10000000;
또는 C ++ 14를 사용할 수 있다면
const int MAX_INDEX = 10'000'000;
1e7
유형의 리터럴 double
이며 일반적으로 double
52 비트 가수가있는 64 비트 IEEE 754 형식입니다. 약 10의 제 2 전원에 대응 열째의 모든 전력이 너무 double
적어도 10의 정수를 나타낼 수 있어야 5 * 3 = 10 (15) , 정확하게 . int
32 비트 인 경우 최대 값 int
은 대략 10 3 * 3 = 10 9입니다 (Google 검색에 "2 ** 31-1"= 2 147 483 647, 즉 대략적인 추정치의 두 배).
따라서 실제로는 현재 데스크톱 시스템 이상에서 안전합니다.
그러나 C ++는 int
16 비트 만 허용 하며, 예를 들어이 작은 임베디드 시스템 int
에서는 정의되지 않은 동작을 가질 수 있습니다.
예를 들어 배열의 모든 요소를 정확하게 반복하는 경우와 같이 정확한 정수 반복 횟수에 대해 반복하려는 의도가있는 경우 부동 소수점 값과 비교하는 것은 정확성상의 이유로 그다지 좋은 생각이 아닐 수 있습니다. 정수를 실수로 암시 적으로 캐스트하면 정수가 0으로 잘 리므로 경계를 벗어난 액세스의 실제 위험이 없으므로 루프가 짧게 중단됩니다.
이제 문제는이 효과가 실제로 언제 시작됩니까? 당신의 프로그램이 그들을 경험할 것인가? 요즘 일반적으로 사용되는 부동 소수점 표현은 IEEE 754입니다. 지수가 0 인 한 부동 소수점 값은 본질적으로 정수입니다. C 배정 밀도는 가수에 대해 52 비트를 부동화하여 정수 정밀도를 최대 2 ^ 52 (약 1e15 정도)의 값으로 제공합니다. f
부동 소수점 리터럴이 단 정밀도로 해석되기를 원하는 접미사 를 지정하지 않으면 리터럴은 배정 밀도가되고 암시 적 변환도이를 대상으로합니다. 따라서 루프 종료 조건이 2 ^ 52 미만인 한 안정적으로 작동합니다 !
Now one question you have to think about on the x86 architecture is efficiency. The very first 80x87 FPUs came in a different package, and later a different chip and as aresult getting values into the FPU registers is a bit awkward on the x86 assembly level. Depending on what your intentions are it might make the difference in runtime for a realtime application; but that's premature optimization.
TL;DR: Is it safe to to? Most certainly yes. Will it cause trouble? It could cause numerical problems. Could it invoke undefined behavior? Depends on how you use the loop end condition, but if i
is used to index an array and for some reason the array length ended up in a floating point variable always truncating toward zero it's not going to cause a logical problem. Is it a smart thing to do? Depends on the application.
ReferenceURL : https://stackoverflow.com/questions/37917806/using-scientific-notation-in-for-loops
'program story' 카테고리의 다른 글
Joda-Time Interval과 비슷한 java.time 클래스가 있습니까? (0) | 2021.01.08 |
---|---|
매니페스트 파일이 다른 Android Studio 두 가지 버전 (0) | 2021.01.08 |
JQuery는 하나의 오류로 여러 필드 유효성 검사 (0) | 2021.01.08 |
Razor : 'Write'메서드에 대한 오버로드는 0 인수를 사용합니다. (0) | 2021.01.08 |
아파치를 시작하고 내 컴퓨터를 계속 죽일 때 많은 아파치 프로세스가 생성되는 것을 어떻게 방지 할 수 있습니까? (0) | 2021.01.08 |