For 루프에서와 같이 정수를 사용할 때 <= 및> =를 피해야합니까? [닫은]


15

학생들에게 등식 테스트는 부동 변수에 대해서는 신뢰할 수 없지만 정수에는 적합하다고 설명했습니다. 내가 사용하고있는 교과서는>와 <보다>와 <보다 읽기 쉽다고 말했다. 어느 정도 동의하지만 For 루프에서 동의합니까? 루프가 시작 및 종료 값을 지정하도록하는 것이 더 명확하지 않습니까?

교과서 작성자가 올바른 내용이 누락 되었습니까?

또 다른 예는 다음과 같은 범위 테스트입니다.

점수> 89 등급 = 'A'인
경우 점수> 79 등급 = 'B'인 경우 ...

왜 그렇게 말하지 않습니까 : if score> = 90?

loops 

11
불행히도 이러한 옵션 사이에는 객관적인 차이가 없기 때문에 사람들이 더 직관적으로 생각하는 것에 대한 여론 조사에 해당하며 설문 조사는 이와 같은 StackExchange 사이트에 적합하지 않습니다.
— Ixrec

1
중요하지 않습니다. 정말.
— Auberon

4
실제로 이것은 객관적으로 대답 할 수 있습니다. 대기 ...
— Robert Harvey

9
@Ixrec 저는 항상 "모범 사례"가 적절한 주제로 간주되지 않는다는 것이 흥미 롭습니다. 누가 코드를 개선하고 더 읽기 쉽게 만들고 싶지 않습니까? 사람들이 동의하지 않으면, 우리 모두 문제의 더 많은 측면을 배우고, 심지어 ... 마음이 바뀔 수 있습니다! 어, 그건 말하기 어려웠어요. 로버트 하비는 객관적으로 대답 할 수 있다고 말했다. 이것은 흥미로울 것입니다.

1
@nocomprende 주로 "모범 사례"는 매우 모호하고 과용 된 용어이기 때문에 언어에 대한 객관적인 사실을 기반으로 유용한 조언을 참조 할 수 있지만 "가장 인기있는 의견"(또는 용어를 사용하는 사람의 의견)을 나타내는 경우가 많습니다 실제로 모든 옵션이 똑같이 유효하고 유효하지 않습니다. 이 경우 Robert가 한 것처럼 특정 유형의 루프로 답변을 제한하고 질문에 완전히 대답하지 않는 의견에서 자신을 지적한 경우에만 객관적인 주장을 할 수 있습니다.
— Ixrec

답변:


36

배열 이 0이 아닌 중괄호 프로그래밍 언어에서는 다음 for과 같이 루프 를 작성하는 것이 일반적입니다 .

for (int i = 0; i < array.Length, i++) { }

이것은 배열의 모든 요소를 ​​통과하며 가장 일반적인 경우입니다. <=또는 의 사용을 피합니다 >=.

이것이 변경되어야 할 유일한 시간은 첫 번째 요소 나 마지막 요소를 건너 뛰거나 반대 방향으로 가로 지르거나 다른 시작점이나 다른 끝점으로 가로 지르는 경우입니다.

컬렉션을 위해 반복자를 지원하는 언어로 다음을 보는 것이 더 일반적입니다.

foreach (var item in list) { }

비교를 완전히 피하십시오.

<=vs 를 언제 사용 해야하는지 에 대한 단단하고 빠른 규칙을 찾고 있다면 규칙 <이 없습니다. 자신의 의도를 가장 잘 나타내는 것을 사용하십시오. 코드가 "보다 작거나 시간당 오십오마일 같음"개념을 표현해야하는 경우 다음 말을해야 <=하지 <.

성적 범위에 대한 질문에 대답하려면 90이 89가 아닌 실제 경계 값이기 때문에>= 90 더 의미 가 있습니다.


9
비교를 완전히 피하지 않고 열거 형 구현으로 이동하여 양탄자 아래에서 스윕합니다. : P
— Mason Wheeler

2
물론, 더 이상 배열을 순회하지 않습니다. 그렇지 않습니까?
— Robert Harvey

4
배열은 for이와 같은 루프 의 가장 일반적인 사용 사례이기 때문 입니다. for여기에 제공된 루프 형식은 약간의 경험이있는 모든 개발자가 즉시 인식 할 수 있습니다. 보다 구체적인 시나리오를 기반으로보다 구체적인 답변을 원하면 질문에 해당 답변을 포함시켜야합니다.
— Robert Harvey

3
"의향을 가장 잘 나타내는 것을 사용하십시오"<-이것!
— Jasper N. Brouwer 19

3
@ JasperN.Brouwer 그것은 제로 프로그래밍 법칙과 같습니다. 모든 스타일 규칙과 코딩 규칙은 명령이 코드의 선명도와 충돌 할 때 가장 부끄러운 일이 아닙니다.
— Idonotexist Idonotexist 6

16

중요하지 않습니다.

:하지만 인수를 위해,의 두 가지 옵션을 분석 할 a > b대 a >= b.

잠깐만! 그것들은 동등하지 않습니다!
OK, 다음 a >= b -1대 a > b또는 a > b대 a >= b +1.

흠, a >b그리고 a >= b보다 모두보기 a >= b - 1와 a >= b +1. 1어쨌든 이 모든 것이 무엇입니까 ? 그래서 나는 임의의을 더하거나 빼서 그 >대신에 >=또는 그 반대로 얻는 것의 이점 이 제거 된다고 주장합니다 1.

그러나 숫자라면 어떨까요? a > 7또는 말하는 것이 낫 a >= 6습니까? 잠시만 요. 우리는 심각하게 사용하는 것이 좋습니다 여부 말다툼 >대 >=와 하드 코딩 변수를 무시? 정말 여부의 문제가된다 그래서 a > DAYS_OF_WEEK보다 더 a >= DAYS_OF_WEEK_MINUS_ONE... 또는 그것이 a > NUMBER_OF_LEGS_IN_INSECT_PLUS_ONE대는 a >= NUMBER_OF_LEGS_IN_INSECT? 그리고 우리는 1변수 이름에서 s를 더하거나 빼는 것으로 돌아 왔습니다 . 또는 임계 값, 제한, 최대를 사용하는 것이 가장 좋은 경우 토론 할 수 있습니다.

그리고 일반적인 규칙이없는 것 같습니다. 비교 대상에 따라 다릅니다.

그러나 실제로 코드에서 개선해야 할 훨씬 더 중요한 사항과 여전히 예외가있는 훨씬 더 객관적이고 합리적인 지침 (예 : 한 줄에 X 자 제한)이 있습니다.


1
일반적으로 규칙은 없습니다. (교과서가 일반적인 규칙을 나타내는 것처럼 보이는 이유를 알고 있지만 그것을 놓아 둘 수는 있습니다.) 내가 놓친 메모라는 새로운 합의가 없습니다.

2
코딩 및 형식화 표준은 순전히 주관적이고 매우 논쟁의 여지가 있기 때문에 @nocomprende. 대부분은 그다지 중요하지 않지만 프로그래머는 여전히 그들에게 거룩한 전쟁을 벌입니다. (조잡한 코드로

1
코딩 표준에 대한 많은 미친 토론을 보았지만 이것만으로도 케이크를 먹을 수 있습니다. 정말 바보입니다.
— JimmyJames

@JimmyJames는 논의에 대해이 인 >대 >=또는 토론 여부에 대한 토론 >대가 >=의미가? p
— Thanos Tintinidis 2016 년

2
“프로그램은 인간이 읽고 컴퓨터를 실행하기위한 용도로만 사용됩니다”– Donald Knuth. 읽고 이해하고 유지하기 가장 쉬운 스타일을 사용하십시오.
— simpleuser

7

계산하여 비용에 차이가없는 <나 >에 비해 <=또는 >=. 빠른 속도로 계산됩니다.

그러나 대부분의 for 루프는 0부터 계산됩니다 (많은 언어가 배열에 대해 0 인덱싱을 사용하기 때문에). 따라서 해당 언어의 표준 for 루프는

for(int i = 0; i < length; i++){
   array[i] = //...
   //...
}

이 작업을 수행 <=하면 off-by one 오류를 피하기 위해 어딘가에 -1을 추가해야합니다

for(int i = 1; i <= length; i++){
   array[i-1] = //...
   //...
}

또는

for(int i = 0; i <= length-1; i++){
   array[i] = //...
   //...
}

물론 언어가 1 기반 색인을 사용하는 경우 <=를 제한 조건으로 사용합니다.

핵심은 조건에 표현 된 값이 문제 설명의 값이라는 것입니다. 읽는 것이 더 깨끗합니다

if(x >= 10 && x < 20){

} else if(x >= 20 && x < 30){

}

반 개방 간격보다

if(x >= 10 && x <= 19){

} else if(x >= 20 && x <= 29){

}

19와 20 사이에 가능한 값이 없다는 것을 알기 위해 수학을 수행해야합니다.


"길이"라는 아이디어를 볼 수 있지만 어딘가에서 가져온 값을 사용하고 시작 값에서 끝 값까지 반복하려는 경우 어떻게해야합니까? 클래스 예제는 5에서 10 사이의 마크 업 백분율입니다. for (markup = 5; markup <= 10; markup ++) ... ? 테스트로 변경 한 이유는 다음과 같습니다. markup <11 ?

6
@nocomprende, 문제 설명의 경계 값이 5와 10이면 약간 변경된 값 대신 코드에 명시 적으로 추가하는 것이 좋습니다.
— ratchet freak

@nocomprende 상한이 매개 변수 인 경우 올바른 형식이 더 분명합니다 for(markup = 5; markup <= MAX_MARKUP; ++markup). 다른 것은 그것을 너무 복잡하게 할 것입니다.
— Navin

1

요점은> 또는> =를 사용 해야하는지 여부가 아니라고 말합니다. 요점은 표현 코드를 작성할 수있는 모든 것을 사용하는 것입니다.

하나를 더하거나 빼야 할 경우 다른 연산자를 사용해보십시오. 좋은 도메인 모델을 시작할 때 좋은 일이 일어난다는 것을 알았습니다. 그런 다음 논리 자체를 씁니다.

bool IsSpeeding(int kilometersPerHour)
{
    const int speedLimit = 90;
    return kilometersPerHour > speedLimit;
}

이것은보다 표현력이 좋습니다

bool IsSpeeding(int kilometersPerHour)
{
    const int speedLimit = 90;
    return kilometersPerHour >= (speedLimit + 1);
}

다른 경우에는 다른 방법이 바람직합니다.

bool CanAfford(decimal price, decimal balance)
{
    return balance >= price;
}

보다 낫다

bool CanAfford(decimal price, decimal balance)
{
    const decimal epsilon = 0e-10m;
    return balance > (price - epsilon);
}

"원초적인 집착"을 용서해주십시오. 분명히 여기에 Velocity 및 Money 유형을 각각 사용하고 싶지만 간결성을 위해 생략했습니다. 요점은 다음과 같습니다. 더 간결하고 해결하려는 비즈니스 문제에 집중할 수있는 버전을 사용하십시오.


2
제한 속도 예는 좋지 않은 예입니다. 90kph 존에서 90kph로가는 것은 과속으로 간주되지 않습니다. 제한 속도가 포함됩니다.
— eidsonator

당신은 절대적으로 정확합니다. 더 나은 예제를 사용하도록 자유롭게 편집하십시오. 점을 완전히 잃지 않기를 바랍니다.
— sara mar

0

귀하의 질문에서 지적했듯이 float 변수에서 동등성을 테스트하는 것은 신뢰할 수 없습니다.

동일에 대한 사실이 보유 <=하고 >=.

그러나 정수 유형에 대해서는 이러한 안정성 문제가 없습니다. 제 생각에는 저자는 어느 쪽이 더 읽기 쉬운 지에 대한 그녀의 의견을 표현 하고 있었습니다 .

당신이 그에게 동의하는지 아닌지는 물론 당신의 의견입니다.


다른 저자들과 그 분야의 회색 머리카락 (일반적으로 회색 머리카락이 있습니다)에 의해 이것은 일반적으로 유지되는 견해입니까? 그것이 "하나의 리포터의 의견"이라면 학생들에게 말할 수 있습니다. 나는 실제로있다. 전에는이 아이디어를 들어 본 적이 없습니다.

저자의 성별은 관련이 없지만 어쨌든 대답을 업데이트했습니다. 나는 해결하려는 특정 문제에 가장 자연스러운 것을 선택 <하거나 <=기반으로 하는 것을 선호합니다 . 다른 사람들이 지적했듯이 FOR 루프 <에서는 C 유형 언어에서 더 의미가 있습니다. 유리한 다른 사용 사례가 <=있습니다. 필요할 때 언제 어디서나 모든 도구를 사용하십시오.
— Dan Pichelman

동의하지 않는다. 이 수 의 정수 유형과 신뢰성 문제가 될 : C에서, 고려하십시오 for (unsigned int i = n; i >= 0; i--)또는 for (unsigned int i = x; i <= y; i++)경우는 y될 일이 UINT_MAX. 죄송합니다.
— jamesdlin

-1

관계의 각각은 <, <=, >=, >그리고 도 == 및 !=두 개의 부동 소수점 값을 비교하기위한 자신의 사용 사례가 있습니다. 각각은 특정한 의미를 가지며 적절한 것을 선택해야합니다.

각각에 대해이 연산자를 정확히 원하는 경우에 대한 예를 제공합니다. (그러나 NaN을 알고 있어야합니다.)

  • f부동 소수점 값을 입력으로 사용 하는 고가의 순수 함수 가 있습니다. 계산 속도를 높이기 위해 가장 최근에 계산 된 값의 캐시, 즉에 대한 조회 테이블을 추가하기로 결정 x합니다 f(x). ==인수를 비교하는 데 실제로 사용하고 싶을 것 입니다.
  • 의미있는 숫자로 나눌 수 있는지 알고 싶 x습니까? 을 사용하고 싶을 것입니다 x != 0.0.
  • 값 x이 단위 간격에 있는지 알고 싶 습니까? (x >= 0.0) && (x < 1.0)올바른 조건입니다.
  • d행렬 의 행렬식 을 계산했으며 양의 한정인지 여부를 말하고 싶습니까? 다른 것을 사용할 이유가 없습니다 d > 0.0.
  • Σ n = 1,…, ∞ n -α가 분기 되는지 알고 싶 습니까? 에 대해 테스트합니다 alpha <= 1.0.

부동 소수점 수학 (일반적으로)은 정확하지 않습니다. 그러나 그것이 당신이 그것을 두려워하고, 그것을 마술로 취급하고, 반드시 두 부동 소수점 수량이 안에 있다고 생각하는 것은 아닙니다 1.0E-10. 그렇게하면 실제로 수학이 깨지고 모든 이상한 일이 발생합니다.

  • 예를 들어 위에서 언급 한 캐시와 퍼지 비교를 사용하면 재미있는 오류가 발생합니다. 그러나 더 나쁜 것은 함수가 더 이상 순수하지 않으며 오류는 이전에 계산 된 결과에 따라 달라집니다!
  • 예,해도 x != 0.0및 y유한 부동 소수점 값입니다 y / x필요가 유한 수 없습니다. 그러나 y / x오버플로로 인해 유한하지 않은지 또는 연산이 수학적으로 잘 정의되지 않았기 때문에 아는 것이 중요합니다 .
  • 입력 매개 변수 x가 단위 간격 [0, 1)에 있어야 하는 전제 조건이있는 함수가있는 경우 x == 0.0or로 호출 할 때 어설 션 오류가 발생하면 실제로 화가납니다 x == 1.0 - 1.0E-14.
  • 계산 한 결정 요인이 정확하지 않을 수 있습니다. 그러나 계산 된 결정 요인이 1.0E-30일 때 행렬이 양의 한정이 아니라고 가정하면 아무것도 얻지 못합니다. 당신이 한 모든 것은 틀린 대답을 할 가능성을 높이는 것입니다.
  • 네, 당신의 주장 alpha은 반올림 에러에 의해 영향을받을 수 있습니다. 따라서 alpha <= 1.0표현식의 실제 수학적 값 alpha이 실제로 1보다 클 수도 있지만 사실 일 수도 있습니다. 그러나이 시점에서 당신이 할 수있는 일은 없습니다.

소프트웨어 엔지니어링에서 항상 그렇듯이 적절한 수준에서 오류를 처리하고 한 번만 처리하십시오. 1.0E-10부동 소수점 수량을 비교할 때마다 (대부분의 사람들이 사용하는 마법의 가치 인 것 같습니다. 왜 그런지 모르겠습니다) 의 순서로 반올림 오류를 추가 하면 곧 1.0E+10…


1
물론 가장 훌륭한 답변은 물론 다른 질문에 대해서만 가능합니다.
— Dewi Morgan

-2

루프에 사용되는 조건부 유형은 컴파일러가 더 좋거나 나쁘게 수행 할 수있는 최적화 종류를 제한 할 수 있습니다. 예를 들면 다음과 같습니다.

uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
  ...  [loop doesn't modify i]

컴파일러는 n이 65535가 아니고 n이 n을 초과하는 것 이외의 방식으로 루프가 종료 되지 않는 한 , 위의 조건으로 인해 n 번째 패스 루프 이후에 루프가 종료되어야한다고 가정 할 수 있습니다 . 이러한 조건이 적용되면 컴파일러는 위 조건 이외의 조건으로 인해 종료 될 때까지 루프가 실행되도록하는 코드를 생성해야합니다.

루프가 대신 다음과 같이 작성된 경우 :

uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
  uint16_t i = ctr+1;
  ... [loop doesn't modify ctr]
}

그러면 컴파일러는 루프가 n 번 이상 실행될 필요가 없으므로보다 효율적인 코드를 생성 할 수 있다고 안전하게 가정 할 수 있습니다.

부호있는 유형의 오버플로는 불쾌한 결과를 초래할 수 있습니다. 주어진:

int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
  total+=i*mult;

컴파일러는 다음과 같이 다시 작성할 수 있습니다.

int total=0;
int start,lim,mult; // Initialize values somehow...
int loop_top = lim*mult;
for (int i=start; i<=loop_top; i+=mult)
  total+=i;

계산에서 오버플로가 발생하지 않으면 이러한 루프는 원래와 동일하게 작동하지만 정수 오버플로가 일반적으로 일관된 줄 바꿈 의미를 갖는 하드웨어 플랫폼에서도 영원히 실행될 수 있습니다.


그래, 나는 그것이 교과서에서 조금 더 멀리 있다고 생각합니다. 아직 고려하지 않았습니다. 컴파일러 최적화는 이해하는 데 유용하며 오버플로는 피해야하지만 실제로는 사람들이 코드를 이해하는 방식과 관련하여 제 질문에 대한 동기 부여가 아니 었습니다. x> 5 또는 x> = 6을 읽는 것이 더 쉬운가요? 글쎄, 그것은 달려있다 ...

Arduino를 작성하지 않는 한 int의 최대 값은 65535보다 약간 높습니다.
— Corey

1
@Corey : 유형이 존재하는 모든 플랫폼에서 uint16_t의 최대 값은 65535입니다. 첫 번째 예에서 uint16_t를 사용했는데, uint32_t보다 uint16_t의 정확한 최대 값을 더 많은 사람들이 알기를 기대하기 때문입니다. 두 경우 모두 동일한 요점이 적용됩니다. 두 번째 예는 "int"의 유형과 관련하여 불가지론 적이며 많은 사람들이 현대 컴파일러에 대해 인식하지 못하는 중요한 행동 포인트를 나타냅니다.
— supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.