简体   繁体   English

检测 C 中的有符号 integer 乘法溢出

[英]Detecting signed integer multiplication overflow in C

I'm writing this code for more than 3 hours already..我写这段代码已经超过 3 个小时了..

I gave up about the overflow thing and tried to google and look it up on stackoverflow.我放弃了关于溢出的事情并试图谷歌并在stackoverflow上查找它。

I did not find any solution besides the one that I wrote in my code as you can see in lines 27-28 (where it returns 0).除了我在代码中编写的解决方案之外,我没有找到任何解决方案,正如您在lines 27-28 (它返回 0)中看到的那样。 But this condition also does not work.但是这个条件也行不通。

#include <stdio.h>

int reverse(int x) {
  int pos = 0;
  int reversed = 0;
  int numOfDigits = 0;
  int tenPower = 1;
  if (x < 0) {
    pos = -x;
  } else
    pos = x;
  while (pos > 0) {
    pos = (pos - (pos % 10)) / 10;
    numOfDigits++;
  }
  while (numOfDigits > 0) {
    for (int i = numOfDigits - 1; i > 0; i--) {
      if (numOfDigits == 1)
        tenPower = 1;
      else
        tenPower *= 10;
    }
//overflow check - does not work
    if (x % 10 != 0 && ((x % 10) * tenPower) / (x % 10) != tenPower)
      return 0;
    reversed += (x % 10) * tenPower;
    numOfDigits--;
    x = (x - (x % 10)) / 10;
    tenPower = 1;
  }
  if (x < 0)
    return -reversed;
  else
    return reversed;
}

int main() {
  int arr[5] = {-30, 120, 1501, 321, 0};
  for (int i = 0; i < 5; i++) {
    printf("Original number is: %d \n", arr[i]);
    printf("Reversed number is: %d \n", reverse(arr[i]));
  }
}

The input that is not working due to overflow is:由于溢出而无法工作的输入是:

1534236469

The error code on leetcode is leetcode 上的错误代码是

Line 25: Char 28: runtime error: signed integer overflow:

1000000000 * 9 cannot be represented in type 'int' [solution.c]

Line: if (x%10 != 0 &&((x%10)*tenPower) / (x%10) != tenPower)行: if (x%10 != 0 &&((x%10)*tenPower) / (x%10) != tenPower)

Other than that, the code is working and every number (positive & negative numbers) is being successfully reversed.除此之外,代码正在运行,并且每个数字(正数和负数)都被成功反转。

I'll be glad to hear you out about a possible solution and also let me know what do you think about my code and the way I decided to complete this task, I know that's the most basic and naïve way to do it, but I'll be glad to know how could I improve it.我很高兴听到你关于可能的解决方案的消息,也让我知道你对我的代码的看法以及我决定完成这项任务的方式,我知道这是最基本和最天真的方法,但我'会很高兴知道我该如何改进它。

The task is:任务是:

Given a signed 32-bit integer x, return x with its digits reversed.给定一个带符号的 32 位 integer x,返回 x 并反转其数字。 If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0.如果反转 x 导致 go 的值超出有符号的 32 位 integer 范围 [-231, 231 - 1],则返回 0。

Assume the environment does not allow you to store 64-bit integers (signed or unsigned).假设环境不允许您存储 64 位整数(有符号或无符号)。

Examples:例子:

Input: x = 123 Output: 321, Input: x=-120 Output = -21输入:x = 123 Output:321,输入:x=-120 Output = -21

The main thing you want to check for overflow is this:您要检查溢出的主要内容是:

reversed += (x % 10) * tenPower;

So what you want to know is if this is true:所以你想知道的是这是否属实:

((x % 10) * tenPower) > INT_MAX

Or this is true:或者这是真的:

(reversed + (x % 10) * tenPower) > INT_MAX

Of course these can never be true in code due to overflow, but we can rearrange the terms:当然,由于溢出,这些在代码中永远不会成立,但我们可以重新排列这些术语:

if ((x % 10) != 0 && (tenPower > INT_MAX / (x % 10)) || 
                      (((x % 10) * tenPower) > INT_MAX - reversed))
    return 0;

You can do something like this.你可以做这样的事情。

int reverse(int n) {
    // 1st overflow checking...
    // Check if the absolute value is greater than INT32_MAX.
    // I converted "int" to "long" to get correct overflow value.
    if (n < 0 && (long) n * -1l > INT32_MAX) {
        return 0;
    }
    
    int res = 0;
    // Convert to absolute value.
    int tmp = n < 0 ? n * -1 : n;
    
    while (tmp > 0) {
        // Get the right most digit and add it to the current result.
        res += tmp % 10;
        // Remove the right most digit.
        tmp /= 10;
        
        // "tmp" still has remaining numbers.
        if (tmp > 0) {
            // 2nd overflow checking...
            // Check if reversed value will be greater than INT32_MAX when appending 0 to right most.
            // I converted "int" to "long" to get correct overflow value.
            if ((long) res * 10l > INT32_MAX) {
                return 0;
            }
            
            // Append 0 to right most value of result.
            // If result is equal to 0, do not append 0.
            res *= res == 0 ? 1 : 10;
        }
    }
    
    // Return result.
    // If original value is negative, return negative result value..
    return n < 0 ? res * -1 : res;
}

OP's code is subject to int overflow in various places OP的代码在各个地方都会发生int溢出

  if (x < 0) { pos = -x; }
  ...
  (x % 10) * tenPower
  ....
  reversed += (x % 10) * tenPower;
  ...
  if (x < 0) return -reversed;

A simple overflow pre-test involves INT_MAX/INT_MIN一个简单的溢出预测试涉及INT_MAX/INT_MIN

  if (x < 0) { 
    if (x < -INT_MAX) { puts("Overflow"); return 0; }
    pos = -x;
  }

  // x is >= 0 here, tenPower >= 1
  int digit = x % 10;
  if (digit > INT_MAX/tenPower)     { puts("Overflow"); return 0; }
  int digit10 = digit * tenPower;
  if (reversed > INT_MAX - digit10) { puts("Overflow"); return 0; }
  reversed += digit10;

Or use stand-alone full range tests .或者使用独立的全方位测试

// Return 1 on overflow
int is_undefined_mult1(int a, int b) {
  if (a > 0) {
    if (b > 0) {
      return a > INT_MAX / b;       // a positive, b positive
    }
    return b < INT_MIN / a;         // a positive, b not positive
  }
  if (b > 0) {
    return a < INT_MIN / b;         // a not positive, b positive
  }
  return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}

  int digit = x % 10;
  if (is_undefined_mult1(digit, tenPower))  { puts("Overflow"); return 0; }
  int digit10 = digit * tenPower;
  if (is_undefined_add1(reversed, digit10)) { puts("Overflow"); return 0; }
  reversed += digit10;

You can use bit_length() to check integer size您可以使用bit_length()检查 integer 大小

if digit.bit_length() >= 32:
        return 0
    else:
        return reversed

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

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