programing

제곱 자릿수를 합산 할 때 음수 또는 0을 명시 적으로 처리해야합니까?

nasanasas 2020. 10. 21. 08:09
반응형

제곱 자릿수를 합산 할 때 음수 또는 0을 명시 적으로 처리해야합니까?


저는 최근에 제 반에서 시험을 받았습니다. 문제 중 하나는 다음과 같습니다.

숫자 n이 주어지면 숫자 제곱 의 자릿수 합계를 반환하는 함수를 C / C ++로 작성합니다 . (다음이 중요합니다). 범위N은 이다 - (10 ^ 7) 10 ^ 7]. 예 : n = 123이면 함수는 14 (1 ^ 2 + 2 ^ 2 + 3 ^ 2 = 14)를 반환해야합니다.

이것은 내가 작성한 함수입니다.

int sum_of_digits_squared(int n) 
{
    int s = 0, c;

    while (n) {
        c = n % 10;
        s += (c * c);
        n /= 10;
    }

    return s;
}

나에게 옳았다. 그래서 이제 시험이 돌아 왔고 선생님이 제가 이해하지 못하는 이유로 모든 점수를주지 않았다는 것을 알게되었습니다. 그에 따르면 내 기능이 완성 되려면 다음 세부 정보를 추가해야했습니다.

int sum_of_digits_squared(int n) 
 {
    int s = 0, c;

    if (n == 0) {      //
        return 0;      //
    }                  //
                       // THIS APPARENTLY SHOULD'VE 
    if (n < 0) {       // BEEN IN THE FUNCTION FOR IT
        n = n * (-1);  // TO BE CORRECT
    }                  //

    while (n) {
        c = n % 10;
        s += (c * c);
        n /= 10;
    }

    return s;
}

이에 대한 주장은 숫자 n 이 [-(10 ^ 7), 10 ^ 7] 범위에 있으므로 음수가 될 수 있다는 것입니다. 그러나 내 버전의 함수가 어디에서 실패하는지 알 수 없습니다. 내가 올바르게 이해한다면의 의미 while(n)while(n != 0), not while (n > 0) 이므로 내 버전의 함수에서 숫자 n 은 루프에 들어가는 데 실패하지 않습니다. 똑같이 작동합니다.

그런 다음 집에있는 내 컴퓨터에서 두 버전의 기능을 모두 사용해 보았고 시도한 모든 예제에 대해 정확히 동일한 답변을 얻었습니다. 따라서 sum_of_digits_squared(-123)sum_of_digits_squared(123)(다시,)와 같습니다 14(명백하게 추가해야하는 세부 사항 없이도). 실제로 화면에 숫자의 자릿수 (중요도가 가장 낮은 것부터 가장 큰 것까지)를 인쇄하려고하면, 123내가받는 경우 3 2 1-123받는 경우 -3 -2 -1(실제로는 흥미 롭습니다). 그러나이 문제에서는 숫자를 제곱하기 때문에 문제가되지 않습니다.

그럼 누가 틀렸어?

편집 : 내 나쁜, 나는 지정하는 것을 잊었고 그것이 중요하다는 것을 몰랐다. 우리의 클래스와 테스트에 사용 C의 버전은 C99 또는이어야한다 . 그래서 (댓글을 읽음으로써) 내 버전이 어떤 식 으로든 정답을 얻을 것이라고 생각합니다.


댓글에 스며 든 토론 요약 :

  • 에 대해 미리 테스트 할 이유가 없습니다 n == 0. while(n)테스트는 완벽하게이 사건을 처리합니다.
  • 교사는 %음수 피연산자 의 결과 가 다르게 정의 된 초기에 여전히 익숙 할 것 입니다. 일부 오래된 시스템 (특히 Dennis Ritchie가 원래 C를 개발 한 PDP-11의 초기 Unix 포함)에서는의 결과 a % b항상 범위 내에 [0 .. b-1]있었습니다. 즉, -123 % 10은 7이었습니다. 이러한 시스템에서 테스트는 사전에 n < 0필요합니다.

그러나 두 번째 항목은 이전 시간에만 적용됩니다. C 및 C ++ 표준의 현재 버전에서 정수 나누기는 0으로 자르도록 정의되어 있으므로 n % 10음수 일 n때도 마지막 숫자 (음수 일 수 있음 )를 보장합니다 n.

그래서 "의미는 while(n)무엇입니까?" 라는 질문에 대한 답입니다 . "과 정확히 동일 while(n != 0)"이며 "이 코드가 양수뿐 아니라 음수에도 제대로 작동 n합니까?" "예, 모든 최신 표준 준수 컴파일러에서"입니다. "그러면 왜 강사가 표시를 했습니까?"라는 질문에 대한 대답 아마도 그들은 1999 년 C와 2010 년 C ++에서 일어난 중요한 언어 재정의를 알지 못했을 것입니다.


귀하의 코드는 완벽합니다.

당신은 절대적으로 옳고 당신의 선생님은 틀 렸습니다. 결과에 전혀 영향을주지 않기 때문에 추가 복잡성을 추가 할 이유가 전혀 없습니다. 그것은 심지어 버그를 소개합니다. (아래 참조)

첫째, n0인지 확인하는 것은 분명히 완전히 불필요하며 이것은 매우 쉽게 알 수 있습니다. 솔직히 말해서 선생님이 이것에 대해 이의가 있다면 선생님의 능력에 의문을 제기합니다. 그러나 나는 누구나 때때로 뇌 방귀를 가질 수 있다고 생각합니다.

두 번째는 좀 더 이해하기 쉽지만 그는 여전히 틀 렸습니다.

이것은 C11 표준 6.5.5.p6이 말하는 것입니다.

몫 a / b가 표현 가능하다면, 식 (a / b) * b + a % b는 a와 같을 것입니다; 그렇지 않으면 a / b 및 a % b의 동작이 정의되지 않습니다.

각주는 다음과 같이 말합니다.

이를 종종 "0으로 자르기"라고합니다.

0으로 잘림은의 절대 값 a/b(-a)/b모든 a의 절대 값과 같음을 b의미 하며 , 이는 코드가 완벽하게 정상임을 의미합니다.

선생님의 코드에 결함이 있습니다

네, 사실입니다. 입력이 INT_MIN있고 아키텍처가 2의 보수를 사용하고 부호 비트가 1이고 모든 값 비트가 0 인 비트 패턴이 트랩 값이 아닌 경우 (트랩 값없이 2의 보수를 사용하는 것이 매우 일반적 임) 교사 코드는 다음 을 산출합니다. 라인에서 정의되지 않은 동작n = n * (-1) . 당신의 코드는-아주 조금이라도- 그의 것보다 습니다. 코드를 불필요하게 복잡하게 만들고 절대적으로 제로 값을 얻음으로써 작은 버그를 도입하는 것을 고려하면 코드가 훨씬 더 좋다고 말하고 싶습니다.

But then again, your teacher explicitly says that n should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. But your code is still much better because this scenario would reintroduce the bug with INT_MIN mentioned above. To avoid this, you can use long instead. Then you will be safe. A long is guaranteed to be able to hold all the values in the range [-2147483647; 2147483647]


I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.

But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:

/* NOTE: This works for negative values, because the modulus gets squared */


NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.

In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.

First is this part right here:

if (n == 0) {
        return 0;
}

In C++, this is basically the same thing as:

if (!n) {
        return 0;
}

That means your while is equivalent to something like this:

while(n != 0) {
    // some implementation
}

That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.

So really, this if statement isn't particularly useful unless I'm mistaken.

The second part is where things get hairy:

if (n < 0) {
    n = n * (-1);
}  

The heart of the issue is is what the output of the modulus of a negative number outputs.

In modern C++, this seems to be mostly well defined:

The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.

And later:

If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.

As the poster of the quoted answer correctly points out, the important part of this equation right here:

(a/b)*b + a%b

Taking an example of your case, you'd get something like this:

-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3 

The only catch is that last line:

If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.

That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.

That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.


EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:

C99 requires that when a/b is representable:

(a/b) * b + a%b shall equal a

And another place:

When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

Does either ANSI C or ISO C specify what -5 % 10 should be?

So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.


A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n) is the same thing as saying while(n != 0) which uses an expression n != 0 that evaluates to either 1 or 0 based on the truth of the expression.

참고URL : https://stackoverflow.com/questions/58224638/do-i-need-to-explicitly-handle-negative-numbers-or-zero-when-summing-squared-dig

반응형