绝对差值是两个数字之间的差值的绝对值.假设我有2int
个变量(x
和y
),我想找出绝对差异.一个简单的解决方案是:
unsigned diff = abs(x-y);
然而,如果发生溢出,则这些调用未定义的行为并给出不正确的结果,例如,如果x
是INT_MIN
,y
是INT_MAX
.这是returns 1
(假设回绕行为),而不是预期的UINT_MAX
.
绝对差值是两个数字之间的差值的绝对值.假设我有2int
个变量(x
和y
),我想找出绝对差异.一个简单的解决方案是:
unsigned diff = abs(x-y);
然而,如果发生溢出,则这些调用未定义的行为并给出不正确的结果,例如,如果x
是INT_MIN
,y
是INT_MAX
.这是returns 1
(假设回绕行为),而不是预期的UINT_MAX
.
好的,以下是可行的方法.@user16217248让我起步.参见that answer岁以下的讨论.
abs((int)num1 - (int)num2)
/// Safely and efficiently return `abs((int)num1 - (int)num2)`
unsigned int abs_num1_minus_num2_int(int num1, int num2)
{
unsigned int abs_diff = num1 > num2 ?
(unsigned int)num1 - (unsigned int)num2 :
(unsigned int)num2 - (unsigned int)num1;
return abs_diff;
}
秘诀是对signed个整数值进行num1 > num2
个三进制比较,然后将它们重新解释为unsigned个整数值,以便在获得绝对值num1 - num2
时允许明确定义的溢出和下溢行为.
以下是我的完整测试代码:
我的eRCaGuy_hello_world份回购中有absolute_value_of_num1_minus_num2.c份:
///usr/bin/env ccache gcc -Wall -Wextra -Werror -O3 -std=gnu17 "$0" -o /tmp/a -lm && /tmp/a "$@"; exit
// For the line just above, see my answer here: https://stackoverflow.com/a/75491834/4561887
#include <limits.h>
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#define TEST_EQ(func, num1, num2, equals) \
printf("%s\n", func((num1), (num2)) == (equals) ? "Passed" : "FAILED")
/// Safely and efficiently return `abs((int8_t)num1 - (int8_t)num2)`
uint8_t abs_num1_minus_num2_int8(int8_t num1, int8_t num2)
{
uint8_t abs_diff = num1 > num2 ?
(uint8_t)num1 - (uint8_t)num2 :
(uint8_t)num2 - (uint8_t)num1;
// debugging
printf("num1 = %4i (%3u); num2 = %4i (%3u); num1-num2=%3u; ",
num1, (uint8_t)num1, num2, (uint8_t)num2, abs_diff);
return abs_diff;
}
/// Safely and efficiently return `abs((int)num1 - (int)num2)`
unsigned int abs_num1_minus_num2_int(int num1, int num2)
{
unsigned int abs_diff = num1 > num2 ?
(unsigned int)num1 - (unsigned int)num2 :
(unsigned int)num2 - (unsigned int)num1;
// debugging
printf("num1 = %11i (%10u); num2 = %11i (%10u); num1-num2=%10u; ",
num1, (unsigned int)num1, num2, (unsigned int)num2, abs_diff);
return abs_diff;
}
int main()
{
printf("Absolute difference tests.\n");
// ---------------
// int8_t types
// ---------------
int8_t num1_8;
int8_t num2_8;
printf("\n");
printf("INT8_MIN = %i, INT8_MAX = %i\n", INT8_MIN, INT8_MAX); // -128, 127
num1_8 = -7;
num2_8 = -4;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 3);
num1_8 = INT8_MIN;
num2_8 = INT8_MAX;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, UINT8_MAX);
num1_8 = INT8_MAX;
num2_8 = INT8_MIN;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, UINT8_MAX);
num1_8 = 100;
num2_8 = 10;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 90);
num1_8 = 10;
num2_8 = 100;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 90);
num1_8 = 10;
num2_8 = 10;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 0);
num1_8 = INT8_MAX;
num2_8 = 1;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 126);
num1_8 = 1;
num2_8 = INT8_MAX;
TEST_EQ(abs_num1_minus_num2_int8, num1_8, num2_8, 126);
// ---------------
// int types
// ---------------
int num1;
int num2;
printf("\n");
printf("INT_MIN = %i, INT_MAX = %i\n", INT_MIN, INT_MAX); // -2147483648, 2147483647
num1 = -7;
num2 = -4;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 3);
num1 = INT_MIN;
num2 = INT_MAX;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, UINT_MAX);
num1 = INT_MAX;
num2 = INT_MIN;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, UINT_MAX);
num1 = 100;
num2 = 10;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 90);
num1 = 10;
num2 = 100;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 90);
num1 = 10;
num2 = 10;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 0);
num1 = INT_MAX;
num2 = 1;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 2147483646);
num1 = 1;
num2 = INT_MAX;
TEST_EQ(abs_num1_minus_num2_int, num1, num2, 2147483646);
return 0;
}
示例运行和输出:
eRCaGuy_hello_world/c$ ./absolute_value_of_num1_minus_num2.c
Absolute difference tests.
INT8_MIN = -128, INT8_MAX = 127
num1 = -7 (249); num2 = -4 (252); num1-num2= 3; Passed
num1 = -128 (128); num2 = 127 (127); num1-num2=255; Passed
num1 = 127 (127); num2 = -128 (128); num1-num2=255; Passed
num1 = 100 (100); num2 = 10 ( 10); num1-num2= 90; Passed
num1 = 10 ( 10); num2 = 100 (100); num1-num2= 90; Passed
num1 = 10 ( 10); num2 = 10 ( 10); num1-num2= 0; Passed
num1 = 127 (127); num2 = 1 ( 1); num1-num2=126; Passed
num1 = 1 ( 1); num2 = 127 (127); num1-num2=126; Passed
INT_MIN = -2147483648, INT_MAX = 2147483647
num1 = -7 (4294967289); num2 = -4 (4294967292); num1-num2= 3; Passed
num1 = -2147483648 (2147483648); num2 = 2147483647 (2147483647); num1-num2=4294967295; Passed
num1 = 2147483647 (2147483647); num2 = -2147483648 (2147483648); num1-num2=4294967295; Passed
num1 = 100 ( 100); num2 = 10 ( 10); num1-num2= 90; Passed
num1 = 10 ( 10); num2 = 100 ( 100); num1-num2= 90; Passed
num1 = 10 ( 10); num2 = 10 ( 10); num1-num2= 0; Passed
num1 = 2147483647 (2147483647); num2 = 1 ( 1); num1-num2=2147483646; Passed
num1 = 1 ( 1); num2 = 2147483647 (2147483647); num1-num2=2147483646; Passed