태그 보관물: floating-point

floating-point

내 경우에 반올림 오류가 발생하지 않더라도 float 숫자의 동등성을 비교하면 주니어 개발자가 오도합니까? STANDARD_LINE 버튼에서 다른 색상을 사용합니다. var MAX=5.0; var DIFF=0.5 var

예를 들어 0,0.5, … 5의 버튼 목록을 표시하고 각 0.5마다 점프합니다. for 루프를 사용하여 STANDARD_LINE 버튼에서 다른 색상을 사용합니다.

var MAX=5.0;
var DIFF=0.5
var STANDARD_LINE=1.5;

for(var i=0;i<=MAX;i=i+DIFF){
    button.text=i+'';
    if(i==STANDARD_LINE){
      button.color='red';
    }
}

이 경우 각 값이 IEEE 754에서 정확하므로 반올림 오류가 없어야하지만 부동 소수점 동등성 비교를 피하기 위해 값을 변경 해야하는 경우 어려움을 겪고 있습니다.

var MAX=10;
var STANDARD_LINE=3;

for(var i=0;i<=MAX;i++){
    button.text=i/2.0+'';
    if(i==STANDARD_LINE/2.0){
      button.color='red';
    }
}

한편으로, 원래 코드는 더 단순하고 나에게 전달됩니다. 그러나 내가 고려하고있는 한 가지가 있습니다 : i == STANDARD_LINE 주니어 팀원을 오도합니까? 부동 소수점 숫자에 반올림 오류가있을 수 있다는 사실을 숨기고 있습니까? 이 게시물에서 댓글을 읽은 후 :

https://stackoverflow.com/questions/33646148/is-hardcode-float-precise-if-it-can-be-represented-by-binary-format-in-ieee-754

부동 소수점 숫자가 정확한지 모르는 많은 개발자가있는 것 같습니다. 내 경우에 부동 소수점 수 평등 비교를 피해야합니까? 아니면 이것에 대해 너무 생각하고 있습니까?



답변

계산중인 모델에서 요구하지 않는 한 항상 연속 부동 소수점 연산을 피합니다. 부동 소수점 산술은 대부분의 주요 오류 소스에 직관적이지 않습니다. 그리고 그것이 아닌 경우 오류가 발생하는 경우를 말하는 것은 훨씬 더 미묘한 차이입니다!

따라서 플로트를 루프 카운터로 사용하는 것은 발생하는 결함이며 최소한 0.5를 사용하는 것이 좋은 이유를 설명하는 뚱뚱한 배경 설명이 필요하며 이는 특정 숫자 값에 따라 다릅니다. 이 시점에서 부동 카운터를 피하기 위해 코드를 다시 작성하는 것이 더 읽기 쉬운 옵션 일 것입니다. 그리고 가독성은 전문가 요구 사항의 계층 구조에서 정확성 옆에 있습니다.


답변

일반적으로 루프는 n 번 무언가를 생각하는 방식으로 작성되어야합니다 . 부동 소수점 인덱스를 사용하는 경우 더 이상 n 번 수행하는 것이 아니라 조건이 충족 될 때까지 실행 하는 문제입니다 . 이 조건이 i<n많은 프로그래머가 기대하는 것과 매우 유사 하면 코드가 실제로 다른 코드를 수행 할 때 코드가 한 가지 일을하는 것처럼 보입니다.이 코드는 프로그래머가 코드를 감추면 쉽게 잘못 해석 할 수 있습니다.

다소 주관적이지만 겸손한 견해로는 정수 색인을 사용하여 고정 된 횟수만큼 반복하기 위해 루프를 다시 작성할 수 있다면 그렇게해야합니다. 따라서 다음 대안을 고려하십시오.

var DIFF=0.5;                           // pixel increment
var MAX=Math.floor(5.0/DIFF);           // 5.0 is max pixel width
var STANDARD_LINE=Math.floor(1.5/DIFF); // 1.5 is pixel width

for(var i=0;i<=MAX;i++){
    button.text=(i*DIFF)+'';
    if(i==STANDARD_LINE){
      button.color='red';
    }
}

루프는 정수로 작동합니다. 이 경우 i정수이며 STANDARD_LINE정수로 강제됩니다. 물론 반올림이 발생한 경우에도 표준 선의 위치가 변경 MAX되므로 정확한 렌더링을 위해 반올림을 방지하기 위해 노력해야합니다. 그러나 부동 소수점 비교에 대해 걱정할 필요없이 정수가 아닌 픽셀 측면에서 매개 변수를 변경할 수 있다는 장점이 있습니다.


답변

정수가 아닌 루프 변수를 사용하는 것이 올바르게 작동하는 것과 같은 경우에도 일반적으로 나쁜 스타일이라는 다른 모든 대답에 동의합니다. 그러나 여기 스타일이 나쁜 또 다른 이유가있는 것 같습니다.

코드는 사용 가능한 선 너비가 정확히 0에서 5.0까지의 0.5의 배수임을 알고 있습니다. 그래야합니까? 그것은 쉽게 변경 될 수있는 사용자 인터페이스 결정처럼 보입니다 (예를 들어, 너비가 커짐에 따라 사용 가능한 너비 사이의 간격이 더 커지기를 원할 수도 있습니다. 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 또는 무엇인가).

코드는 사용 가능한 선 너비가 모두 부동 소수점 숫자와 10 진수로 “좋은”표현을 가지고 있음을 “알고”있습니다. 그것은 또한 변할 수도있는 것 같습니다. (어느 시점에서 0.1, 0.2, 0.3, …을 원할 수 있습니다.)

여러분의 코드는 버튼에 넣을 텍스트가 자바 스크립트가 부동 소수점 값으로 바뀌는 것임을 “알고”있습니다. 그것은 또한 변할 수도있는 것 같습니다. (예를 들어 언젠가는 1/3과 같은 너비를 원할 것입니다.이 너비는 0.33333333333333 또는 다른 것으로 표시하지 않을 것입니다. 또는 “1.5”와 일관성을 유지하기 위해 “1”대신 “1.0”을보고 싶을 수도 있습니다. .)

이것들은 모두 하나의 약점의 표현처럼 느껴집니다. 이것은 일종의 레이어 혼합입니다. 이러한 부동 소수점 숫자는 소프트웨어의 내부 논리의 일부입니다. 버튼에 표시되는 텍스트는 사용자 인터페이스의 일부입니다. 여기 코드에서보다 분리되어 있어야합니다. “이 중 어느 것이 강조 표시되어야합니까?”와 같은 개념 사용자 인터페이스 문제이며 아마도 부동 소수점 값에 묶여서는 안됩니다. 그리고 여기서 루프는 실제로 선 너비가 아닌 버튼 위의 루프 입니다. 그렇게하면 정수가 아닌 값을 갖는 루프 변수를 사용하려는 유혹이 사라집니다. 연속적인 정수 또는 for … in / for … of 루프를 사용하는 것입니다.

제 생각에는 정수가 아닌 숫자를 반복하려고 하는 대부분의 경우는 다음과 같습니다. 숫자 문제와 전혀 관련이없는 다른 이유가 있으며 코드가 다르게 구성되어야하는 이유가 있습니다. ( 모든 경우가 아니라 ; 일부 수학적 알고리즘이 정수가 아닌 값에 대한 루프로 가장 깔끔하게 표현 될 수 있다고 상상할 수 있습니다.)


답변

하나의 코드 냄새가 그런 식으로 루프에서 수레를 사용하고 있습니다.

루핑은 여러 가지 방법으로 수행 할 수 있지만 99.9 %의 경우 1 씩 증가해야합니다. 그렇지 않으면 주니어 개발자 만이 아니라 혼란이있을 것입니다.


답변

예, 이것을 피하고 싶습니다.

부동 소수점 숫자는 의심없는 프로그래머에게 가장 큰 함정 중 하나입니다. 부동 소수점 평등 테스트에 따라 돈을 부동 소수점으로 표시하는 것까지 모두 큰 문제입니다. 하나의 플로트를 다른 플로트에 추가하는 것은 가장 큰 범죄자 중 하나입니다. 이와 같은 것에 관한 많은 과학 문헌이 있습니다.

예를 들어 삼각법, 플로팅 함수 그래프 등과 같이 실제 수학 계산을 수행 할 때와 같이 적절한 위치에 부동 소수점 숫자를 정확하게 사용하고 연속 연산을 수행 할 때는 매우주의해야합니다. 평등은 바로입니다. IEEE 표준에 의해 어떤 특정 숫자 집합이 정확한지에 대한 지식은 매우 희귀하며 절대 그것에 의존하지 않습니다.

귀하의 경우, Murphys Law에 따르면 경영진이 0.0, 0.5, 1.0 …이 아니라 0.0, 0.4, 0.8 … 또는 그 밖의 것을 갖기를 원하는 지점 이 생길 것입니다 . 당신은 즉시 질식 할 것이고, 당신의 하급 프로그래머 (또는 당신 자신)는 문제를 찾을 때까지 길고 열심히 디버깅 할 것입니다.

특정 코드에서는 실제로 정수 루프 변수가 있습니다. i숫자가 아닌 th 버튼을 나타냅니다 .

그리고 아마도, 명확성을 기하기 위해 글을 쓰지 i/2않고 i*0.5무슨 일이 일어나고 있는지 분명히 알 수있을 것입니다.

var BUTTONS=11;
var STANDARD_LINE=3;

for(var i=0; i<BUTTONS; i++) {
    button.text = (i*0.5)+'';
    if (i==STANDARD_LINE) {
      button.color='red';
    }
}

참고 : 주석에서 지적했듯이 JavaScript에는 실제로 별도의 정수 유형이 없습니다. 그러나 최대 15 자리의 정수는 정확하고 안전합니다 ( https://www.ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer 참조 ). 정수 또는 정수가 아닌 정수에서 작동하기가 더 혼동스럽고 오류가 많음 “)”정신 “에 별도의 유형을 갖는 것이 적절합니다. 매일 사용하는 (루프, 화면 좌표, 배열 인덱스 등) NumberJavaScript로 표시되는 정수는 놀라운 일이 아닙니다 .


답변

나는 당신의 제안 중 하나가 좋다고 생각하지 않습니다. 대신 최대 값과 간격을 기반으로 버튼 수에 대한 변수를 소개합니다. 그런 다음 버튼 자체의 인덱스를 반복하는 것은 간단합니다.

function precisionRound(number, precision) {
  let factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}

var maxButtonValue = 5.0;
var buttonSpacing = 0.5;

let countEstimate = precisionRound(maxButtonValue / buttonSpacing, 5);
var buttonCount = Math.floor(countEstimate) + 1;

var highlightPosition = 3;
var highlightColor = 'red';

for (let i=0; i < buttonCount; i++) {
    let buttonValue = i / buttonSpacing;
    button.text = buttonValue.toString();
    if (i == highlightPosition) {
        button.color = highlightColor;
    }
}

더 많은 코드 일 수 있지만 더 읽기 쉽고 강력합니다.


답변

루프 카운터를 값으로 사용하는 대신 표시하고있는 값을 계산하여 모든 것을 피할 수 있습니다.

var MAX=5.0;
var DIFF=0.5
var STANDARD_LINE=1.5;

for(var i=0; (i*DIFF) < MAX ; i=i+1){
    var val = i * DIFF

    button.text=val+'';

    if(val==STANDARD_LINE){
      button.color='red';
    }
}