繁体   English   中英

写一个程序,读取一个Integer。Output另一个integer其中偶数位保留,奇数位减1,

[英]Write a program, which reads an Integer. Output another integer where the even digits are retained and odd digits are decremented by 1,

这是我的代码:

#include <stdio.h>
#include <math.h>

int main() {
    int num, i = 0, new_num = 0, u;

    printf("Enter a number: ");
    scanf("%d", &num);
    while (num > 0) {
        u = num % 10;
        if (u % 2 == 0)
            u = u;
        if (u % 2 == 1)
            u = u - 1;
        new_num = new_num + u * pow(10, i);
        num = num / 10;
        i++;
    }
    printf("The new number is: %d", new_num);
    return 0;
}

现在,当我在 gcc(VS 代码)中执行此操作时,对于 2 位数,一切正常。 但是对于超过三位的数字,我得到了一个错误。 比如输入= 23145输出= 22043 但我期待 output= 22044

另外,如果我在 DevC/C++ 中运行相同的代码,也没有错误。

谁能帮我解决这个问题?

您的程序在我的系统上生成预期的 output: 2204423145 ,但这可能取决于pow function 的实现。

您得到不同 output 的原因可能是 C 库中pow() function 的精度问题的副作用:如果pow(x, y)实现为exp(y * log(x)) ,则结果为xy的整数值可能非常接近但不如实际的整数值,导致转换为int产生前面的 integer。一些 C 库作者做了一个特殊情况的整数 arguments 来避免这个问题,但强烈推荐避免 integer 算术的浮点函数以防止此类棘手的问题。

我会建议您对代码进行更多更改:

  • 测试scanf()的返回值。

  • 删除if (u % 2 == 0) u = u; 部分,它没有影响。

  • 在任何情况下,都应该有一个else子句,以便在测试奇数时不使用前一个案例的结果。

  • 不要使用浮点数 function pow() :只保留一个乘数变量并在循环中更新它。

  • 该程序不处理负数。

这是修改后的版本:

#include <stdio.h>

int main() {
    int num, new_num = 0, pow10 = 1;

    printf("Enter a number: ");
    if (scanf("%d", &num) != 1)
        return 1;
    while (num != 0) {
        int digit = num % 10;
        /* decrement odd digits absolute value */
        digit -= digit % 2;
        new_num = new_num + digit * pow10;
        pow10 = pow10 * 10;
        num = num / 10;
    }
    printf("The new number is: %d\n", new_num);
    return 0;
}

注意digit -= digit % 2; 将递减正奇数位并实际递增负奇数位,这实际上总是递减奇数位的绝对值。 这样正值和负值都可以正确处理。

问题似乎是使用返回双精度值的 function pow

如果您正在处理整数,那么最好避免使用由于可能的截断而返回双精度的函数,然后双精度将转换为 integer。

还要注意用户可以输入负数。 您的程序允许这样做。 在这种情况下,您的程序也会产生不正确的结果。

我会按以下方式编写程序

#include <stdio.h>

int main( void )
{
    while (1)
    {
        const int Base = 10;
        int num;

        printf( "Enter a number (0 - exit): " );

        if (scanf( "%d", &num ) != 1 || num == 0) break;

        int new_num = 0;
        
        for (int tmp = num, multiplier = 1; tmp != 0; tmp /= Base)
        {
            int digit = tmp % Base;

            if (digit % 2 != 0)
            {
                digit += ( digit < 0 ? 1 : -1 );
            }
            new_num = new_num + multiplier * digit;
            multiplier *= Base;
        }

        printf( "The original number is %d and the new number is: %d\n", 
                num, new_num );
        putchar( '\n' );
    }
}

程序 output 是

Enter a number (0 - exit): -123456789
The original number is -123456789 and the new number is: -22446688

Enter a number (0 - exit): 123456789
The original number is 123456789 and the new number is: 22446688

Enter a number (0 - exit): 0

如果即使是负数也要加 -1 那么你应该用这个 if 语句代替

if (digit % 2 != 0)
{
    digit += ( digit < 0 ? 1 : -1 );
}

对于这个

if (digit % 2 != 0)
{
    digit = ( digit -1 ) % Base;
}

在这种情况下,程序 output 可能看起来像

Enter a number (0 - exit): -123456789
The original number is -123456789 and the new number is: -224466880

Enter a number (0 - exit): 123456789
The original number is 123456789 and the new number is: 22446688

Enter a number (0 - exit): 0

也就是说,在这种情况下,负值-123456789的新值将是-224466880

在我的 Visual Studio Code 实例中,对于输入 23145,我确实发现 22044 是 output。

我猜分歧来自pow(10,i)的转换。 Pow function in C 返回一个 double,这不是你真正想要的。 我强烈建议不要将pow function 用于 integer 算术。

一个解决方案可能是:

uint16_t i = 0u;
uint16_t current_digit = 0u, decimal_digit = 1u;

uint16_t new_number = 0u;
uint16_t number = 23145u;

while(number > 0u) {
    current_digit = number % 10;

    if (current_digit % 2) {
        current_digit = current_digit - 1;
    }
    new_number = new_number + current_digit * decimal_digit;
    decimal_digit *= 10u;
    number /= 10;
    i++;
}
printf("The new number is: %d", new_number);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM