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 > ba >= b.

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

흠, a >b그리고 a >= b보다 모두보기 a >= b - 1a >= 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.0y유한 부동 소수점 값입니다 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.