两个正数相乘为什么结果是负数

本文详述了使用Spark处理Hive表数据时遇到的正数相乘结果为负数的问题,分析了原因在于int类型取值范围限制,提出了转换字段类型至Double或调整计算策略的解决方案。

前言

说来实在惭愧,用spark处理hive表中的数据时,出现了两个正数相乘最后结果显示为负数后我的第一反应竟然有点懵逼,充分说明了自己在使用数据时,对Hive表中的字段类型没有进行充分的了解,当时,第二反应才想起是数据类型导致的数据超出范围了,这个还得归结在当时创建Hive表的时候,没有充分对表中每个字段要存储的数据类型进行充分调查

Java基本数据类型及范围

分类数据类型字节取值范围默认值
布尔boolean1false,truefalse
整数字节型byte1-128~127,即-2^7 ~ 2^7-10
整数短整型short2-32768~32767,即-2^15 ~ 2^15-10
整数整型int4-2147483648~2147483647,即-2^31 ~ 2^31-10
整数长整型long8-9 223 372 036 854 775 808~9 223 372 036 854 775 807,即-2^63 ~ 2^63-10
字符char20~65535,\u0000 ~ \uFFFF\u0000
浮点数单精度浮点数float4负数范围:-3.4028234663852886 × 10^38 ~ -1.40129846432481707 × 10^-45,正数范围:1.40129846432481707 × 10^-45~3.4028234663852886 × 10^380.0f
浮点数双精度浮点数float8负数范围:-1.7976931348623157 × 10^308 ~ -4.94065645841246544 × 10^-324,正数范围:4.94065645841246544 × 10^1.7976931348623157 × 10^3080.0

问题简述

  • Hive表一个字段的类型
total_flow          	int
  • 我的操作
// avg_tf是个正数
total_flow * 25 / avg_tf
  • 出现的问题
    通过抽查total_flow = 113716790,乘以25后为3411503700,avg_tf = 322183360,正常结果约为38,可现实结果约为-1.75…

  • 原因分析
    int最大取值为2147438647,而现在已经达到3411503700,显然远远超过了int的取值范围,因此出现这样的原因

  • 解决方案
    (1)修改字段的类型为Double
    (2)在计算的时候,将字段的换算成量级小一下的,防止超出范围,比如我这里给分子分母同时除以1000,或者先除后乘

后记

这里做一个简答测试:int最大值+1的结果?

public class Type_Of_Data {
    public static void main(String[] args) {
       int a = 2147483647;
       int b = 1;
       int c = a + b;
        System.out.println(c);
    }
}

结果:

-2147483648

为什么超过int最大范围结果成了负数?

这个和计算机如何存储二进制有关,在电脑里是以补码出现的。第一位是符号位。0为正,1为负,当正的除了符号位全为1时候,要是再加一就进位了,导致符号位为1,其他为0,再换成10进制就是你这个数了

递归实现两个整数相乘的代码可以通过将乘法转化为重复加法来完成。例如,`a * b` 可以理解为 `a` 加上自己 `b` 次。为了提高效率并避免深度递归导致栈溢出,我们可以使用类似快速幂的思想进行优化——即通过位运算减少递归次数。 下面是使用递归实现整数乘法的 C++ 代码(支持正负数): ```cpp #include <iostream> // 辅助函数:使用递归实现无符号整数的快速乘法(避免溢出问题较小的情况下) long long multiplyRecursiveHelper(long long a, unsigned int b) { if (b == 0) return 0; if (b == 1) return a; // 如果 b 是偶数:a * b = a*2 * (b/2) if (b % 2 == 0) { return multiplyRecursiveHelper(a + a, b / 2); } else { // 如果 b 是奇数:a * b = a + a*(b-1) return a + multiplyRecursiveHelper(a, b - 1); } } // 主函数:处理正负号情况 long long multiply(int x, int y) { // 处理边界情况 if (x == 0 || y == 0) return 0; // 记录结果的符号 bool isNegative = (x < 0) ^ (y < 0); // 异或判断是否一正一负 // 转换为非负数处理 long long absX = x < 0 ? -static_cast<long long>(x) : static_cast<long long>(x); long long absY = y < 0 ? -static_cast<long long>(y) : static_cast<long long>(y); // 使用递归计算绝对值的乘积 long long result = multiplyRecursiveHelper(absX, static_cast<unsigned int>(absY)); // 根据符号返回结果 return isNegative ? -result : result; } // 示例用法 int main() { int a = 13, b = -6; std::cout << a << " * " << b << " = " << multiply(a, b) << std::endl; a = 7; b = 8; std::cout << a << " * " << b << " = " << multiply(a, b) << std::endl; return 0; } ``` ### 解释: 1. **递归思想**:我们将乘法 `a * b` 分解成更小的问题: - 若 `b` 为偶数,则 `a * b = (a + a) * (b / 2)` - 若 `b` 为奇数,则 `a * b = a + a * (b - 1)` 这类似于“快速幂”算法,时间复杂度从 O(b) 降低到 O(log b)。 2. **符号处理**:通过异或判断结果正负,然后对绝对值进行递归计算。 3. **防止溢出**:使用 `long long` 防止中间结果溢出。 4. **递归终止条件**:当 `b == 0` 返回 0,`b == 1` 返回 `a`。 5. **效率提升**:相比朴素递归(每次减1),该方法显著减少了递归层数。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRivers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值