계수 나눗셈 (%)이 정수에서만 작동하는 이유는 무엇입니까?


79

최근에 모듈러스 나누기를 사용하여 쉽게 해결할 수 있는 문제발생 했지만 입력은 부동 소수점이었습니다.

주기 함수 (예 sin:)와주기 범위 내에서만 계산할 수있는 컴퓨터 함수 (예 : [-π, π])가 주어지면 모든 입력을 처리 할 수있는 함수를 만듭니다.

"명백한"해결책은 다음과 같습니다.

#include <cmath>

float sin(float x){
    return limited_sin((x + M_PI) % (2 *M_PI) - M_PI);
}

왜 이것이 작동하지 않습니까? 이 오류가 발생합니다.

error: invalid operands of types double and double to binary operator %

흥미롭게도 Python에서 작동합니다.

def sin(x):
    return limited_sin((x + math.pi) % (2 * math.pi) - math.pi)

20
π는 3.14와 같지 않으며 실제로 부동 소수점 유형으로 표현할 수 없습니다. 컴퓨팅 sin(x)의 큰 값을 x실제로하는 것은 파이의 유한 근사에 의해 얻을 수없는 매우 어려운 초월 인수 환원 공정을 필요로한다.
R .. GitHub STOP HELPING ICE

3
이것은 거의 확실하게 숙제이므로 부동 소수점 오류는 과제의 범위를 벗어나거나 더 엄격한 수치 분석에 대한 논의로 이어질 수 있습니다. 어느 쪽이든 fmod강사가 찾고있는 것입니다.
Dennis Zickefoose

2
그것은 다른 SO 질문 (읽는 동안 와서 단지 뭔가, 숙제 아니다 stackoverflow.com/questions/6091837/... )
브랜든 긴

2
좋아, 나는 내 진술에서 더 정확해야했다. 내 요점은 인수가 무한히 커질 수 있다면 (배정 밀도 지수 크기뿐만 아니라) 파이의 유한 근사치로 충분하지 않다는 것입니다. double의 경우, 예, pi의 매우 긴 근사값으로 충분합니다.
R .. GitHub의 STOP 돕기 ICE

1
@aschepler : 문제를 이해하지 못했다고 생각합니다.
R .. GitHub STOP HELPING ICE

답변:


76

"나머지"의 일반적인 수학적 개념은 정수 나눗셈에만 적용 할 수 있기 때문입니다. 즉, 정수 몫을 생성하는 데 필요한 나눗셈.

"나머지"개념을 실수로 확장하려면 실제 피연산자에 대해 정수 몫을 생성하는 새로운 종류의 "하이브리드"연산을 도입해야합니다 . Core C 언어는 이러한 작업을 지원하지 않지만 표준 라이브러리 기능과 C99의 기능 으로 제공됩니다 . (이러한 함수는 동일하지 않고 몇 가지 특징이 있습니다. 특히 정수 나누기의 반올림 규칙을 따르지 않습니다.)fmodremainder


7
98 표준의 % 정의에서 "(a / b) * b + a % b는 a와 같습니다." 부동 소수점 유형의 (a/b)*b경우 a[부동 소수점 유형에 대해 그러한 명령문을 작성할 수있는 한] 이미 같으 므로 a%b특별히 유용하지 않습니다.
Dennis Zickefoose

1
@Dennis : 사실, 대수적으로 필드에서 나머지는 항상 0 %입니다. 부동 소수점 에 대한 연산자 의 가장 적절한 정의는 a-(a/b)*b0 또는 매우 작은 값이 될 것입니다.
R .. GitHub STOP HELPING ICE

7
@Dennis : "floor (a / b) * b + a % b = a"를 요구하여이 공식을 쉽게 수정할 수 있습니다. 정수의 경우 floor (a / b) = a / b입니다.
vog

C 스타일 정수 나누기는 바닥이 아닌 잘림을 사용하지만 점은 그대로 유지됩니다.
dan04 jul.

18
-1 Re ""나머지 "의 일반적인 수학적 개념은 정수 나눗셈에만 적용 할 수 있습니다.", 모듈로 산술의 수학적 개념은 부동 소수점 값에도 적용됩니다. 이것은 Donald Knuth가 그의 고전에서 논의한 첫 번째 문제 중 하나입니다 . 컴퓨터 프로그래밍 기술 (1 권). 즉, 한때 기본 지식이었습니다. 오늘날 학생들은 IMHO라는 교육비를받지 못하고 있습니다.
건배와 hth. - 알프

52

당신은 fmod ()를 찾고 있습니다.

귀하의 질문에 더 구체적으로 대답하려고합니다. 이전 언어에서는 %연산자가 정수 모듈 식 분할로 정의되었고 최신 언어에서는 연산자의 정의를 확장하기로 결정했습니다.

편집 : 내가 추측을 내기한다면, 모듈 식 산술의 아이디어가 숫자 이론에서 유래하고 특히 정수를 다루기 때문이라고 말할 것입니다.


9
"이전 언어"-APL은 1960 년대로 거슬러 올라가며 모듈로 연산자 "|" 정수 및 부동 소수점 데이터 (스칼라, 벡터, 행렬, 텐서 등) 모두에서 작동합니다. C의 "%"모듈로 연산자가 부동 소수점 숫자와 함께 사용되는 경우 fmod와 동일한 기능을 수행 할 수없는 이유가 없습니다.
rcgldr 2014-08-23

@rcgldr 디자인 목표에는 부동 소수점 모듈로가 필요하지 않았습니다. C는 Unix를 컴파일하고 OS에 필요한 어셈블리 언어의 양을 제한하기 위해 구현되었습니다. "C는 명령형 절차 언어입니다. 비교적 간단한 컴파일러를 사용하여 컴파일하고, 메모리에 대한 저수준 액세스를 제공하고, 기계 명령에 효율적으로 매핑되는 언어 구조를 제공하고, 최소한의 런타임 지원을 요구하도록 설계되었습니다." en.wikipedia.org/wiki/C_(programming_language)
하퍼

1
@harper-C는 정수와 동일한 구문을 사용하여 더하기, 빼기, 곱하기 및 나누기와 같은 부동 소수점 산술을 포함하므로 동일한 구문 (%)을 사용하여 모듈로를 포함 할 수없는 이유를 알 수 없습니다. . 포함 여부는 임의적으로 보입니다.
rcgldr

16

확실히 말할 수는 없지만 대부분 역사적이라고 생각합니다. 상당수의 초기 C 컴파일러는 부동 소수점을 전혀 지원하지 않았습니다. 나중에 추가되었지만 완전히는 아니지만 대부분 데이터 유형이 추가되었고 언어에서 가장 원시적 인 작업이 지원되었지만 나머지는 모두 표준 라이브러리에 남았습니다.


1
내가 목록을 읽는 동안 내가 본 첫 번째 합리적인 대답은 +1입니다. 사실, 이제 모든 것을 읽었으므로 이것이 유일한 합리적인 대답입니다.
건배와 hth. - 알프

나 에게서도 뒤늦은 +1. 저는 6809 및 Z80 임베디드 시스템 용 C로 작성했습니다. C 런타임 라이브러리를 포함 할 공간을 감당할 수 없습니다. 나만의 시작 코드도 작성해야했습니다. 부동 소수점 내가 :) 감당할 수없는 사치
리처드 스

12

%C와 C ++ 의 모듈로 연산자 는 두 개의 정수에 대해 정의되지만 fmod()double과 함께 사용할 수 있는 함수가 있습니다.


4
이는 영업 이익의 질문에 대한 대답이지만, 영업 이익은 일을하려고 무엇의 근본적인 문제를 무시 : sin(fmod(x,3.14))또는 sin(fmod(x,M_PI))동일하지 않은 sin(x)큰 값 x. 실제로 값은 2.0만큼 다를 수 있습니다.
R .. GitHub STOP HELPING ICE

2
@R .. : 맞아요.하지만 그건 다른 질문이고, 그 주제에 대한
Mark Elliot

@R-나는 그것을 올바르게하기 위해 방정식을 고쳤다. 실제 방정식은 요점이 아니 었습니다 (테스트 할 기능이 있으면 알아 내기가 상당히 쉬웠습니다).
Brendan Long

%나머지 연산자 가 아니고 모듈로 연산자가 아닙니까?
chux-Monica 복원

7

제약은 표준에 있습니다.

C11 (ISO / IEC 9899 : 201x) §6.5.5 곱셈 연산자

각 피연산자는 산술 유형을 가져야합니다. % 연산자의 피연산자는 정수 유형을 가져야합니다.

C ++ 11 (ISO / IEC 14882 : 2011) §5.6 곱셈 연산자

* 및 /의 피연산자는 산술 또는 열거 유형을 가져야합니다. %의 피연산자는 정수 또는 열거 유형을 가져야합니다. 일반적인 산술 변환은 피연산자에서 수행되며 결과 유형을 결정합니다.

해결책 은를 사용하는 것입니다. 이것이 바로 C99 Rationale §6.5.5 곱셈 연산자 에 따라 fmod의 피연산자 %가 정수 유형으로 제한되는 이유입니다 .

C89위원회는 % 연산자를 플로팅 유형에 대한 작업으로 확장하는 것을 거부했습니다.



2

% 연산자는 숫자의 REMAINDER (계수에 대한 다른 이름)를 제공합니다. C / C ++의 경우 정수 연산에 대해서만 정의됩니다. 파이썬은 조금 더 넓으며 숫자를 몇 번 나눌 수 있는지 나머지에 대해 부동 소수점 숫자의 나머지를 얻을 수 있습니다.

>>> 4 % math.pi
0.85840734641020688
>>> 4 - math.pi
0.85840734641020688
>>> 

2
나머지는 '모듈러스의 또 다른 이름' 이 아닙니다 !! 참조 : stackoverflow.com/questions/13683563/… 또는 math-pov에서 : math.stackexchange.com/questions/801962/… 간단히 말해서 : 모듈로와 나머지는 양수에 대해서만 동일하며 다른 예는 나머지가 그렇지 않다는 것입니다. t 나침반을 돌게하십시오 (시계 반대 방향). 내가 :P
다운 투표

2

%당신이 두 유형의 두 숫자의 나머지 찾을하려고 할 때 연산자는, C ++에서 작동하지 않습니다 Float또는 Double.

따라서 / 에서 fmod함수를 사용해 보거나 해당 헤더 파일을 사용하지 않도록 다음 코드 줄을 사용할 수 있습니다.math.hcmath.h

float sin(float x) {
 float temp;
 temp = (x + M_PI) / ((2 *M_PI) - M_PI);
 return limited_sin((x + M_PI) - ((2 *M_PI) - M_PI) * temp ));

}


1

"모듈로 산술의 수학적 개념은 부동 소수점 값에도 적용됩니다. 이것은 Donald Knuth가 그의 고전 The Art of Computer Programming (volume I)에서 논의한 첫 번째 문제 중 하나입니다. 즉, 한때 기본 지식이었습니다."

부동 소수점 모듈러스 연산자는 다음과 같이 정의됩니다.

m = num - iquot*den ; where iquot = int( num/den )

표시된대로 부동 소수점 숫자에 대한 % 연산자의 no-op은 표준과 관련된 것으로 보입니다. CRTL은 fp 번호에 대해 %를 수행하기 위해 'fmod'와 일반적으로 'remainder'도 제공합니다. 이 두 가지의 차이점은 중간 'iquot'반올림을 처리하는 방법에 있습니다.

'remainder'는 가장 가까운 반올림을 사용하고 'fmod'는 단순 자르기를 사용합니다.

자체 C ++ 숫자 클래스를 작성하는 경우 오버로드 된 연산자 %를 포함하여 no-op 레거시를 수정할 수있는 방법은 없습니다.

친애하는

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.