关于负数取余的讨论

看到知乎上一哥们的回答,觉得既经典又富含趣味:
关于负数的余数,楼上很多网友已经阐述了纯数学概念上的意义。我想从另一个角度说说我的看法。先明确一点:我们讨论的是“被除数”(分子)是负整数,而除数(分母)是正整数的情况。

先看一个例子: (-17) mod 5 =?

答案一: (-17) = (-3)*5 + (-2),所以余数是 -2 。

答案二: (-17) = (-4)*5 + (+3),所以余数是 +3 。

首先,从“纯数学”概念上说,两个答案都“对”,就好像解方程的时候出现“复数解”一样,也是一个解。所以各种编译器按照各自的逻辑来产生余数。

但是,从人类思维角度上说,“负数”的起源是因为“不足、欠缺”,使用负数是为了知道有多欠缺,然后去补救。从这个角度才能正确理解“负数的余数”的实际意义(区别于纯数学概念)。

打个比方,你和另外5个同学住在宿舍里,你很勤快,那5个人很懒,让你帮忙买早餐,比如说,油条、豆浆 …… 你提着他们的早餐回来,对他们说:“一共17块钱。”就是说,他们5个人一共欠你17元。平均每人给你 17/5=3.4元。

于是他们就翻箱倒柜 —— 不是没有钱,而是在找零钱,每人都要拿0.4元,嗯,各位看官不妨找找自己身上有没有4毛钱 …… 结果就是,都找不到零钱,怎么办?于是有两种办法:

办法一:每人给你3块钱,但是总共还欠你2块钱,余数= -2

办法二:每人给你4块钱,但是你要给回他们3块钱,余数 = +3

现在问题是:各位作为人类,倾向于采用哪一个办法?

上面说了,人类之所以使用负数,是为了知道“不足”,然后进行补救。现在既然欠了钱要还,我想那5位同学都会给你4块钱,倒不是说他们是为了给你3块钱跑腿费,而是他们想“了(liao)了(le)这笔账”,他们不想5个人 每人都欠你0.4元的人情(何况你还真的跑腿了),既然都还钱了,为什么还要留一笔“遗留问题”呢?

所以, 从人类思维习惯和实际需要来说(再说一遍:区别于纯数学概念),无论被除数(分子)是正数还是负数,余数都应该取正数,这样才符合人类的思维习惯和实际需要。

题外话:就好像除数(分母)通常是正数一样,如果用一个负数来做除数(分母),人们会觉得很别扭,很难理解。

其实,如果允许余数可以是负数的话,那么 23%5 同样有两个答案,可以看作 +3,也可以是 -2,但我相信没有人会用 -2,第一反应肯定是用 +3 。

现在回到题主的问题: (-7)%10=? 是 +3 还是 -7 ?

如果说人话,就是:现在欠你7块钱,由10个人来还,怎么办?

办法一:每人还你一块钱,结果多出3块钱,余数=+3

办法二:每人还给你 0元,余数 = -7 ,结果最后,一切照旧,依然欠你7块钱 ……
数学语言说:向负无穷取值还是向0取值 ……

==========分割线==========分割线==========分割线==========分割线==========

说到这里,可能有人说,数学不是凭情感、看习惯的,数学是严谨的。

我非常赞同这个观点,对于数学这种推崇严密和严谨的科学,同样的操作数、同样的运算符,必然得到同样的运算结果。那么,余数这种“可正可负”的“双重标准”是致命的 Fatal Error ,会摧毁数学大殿的根基。试想一下,-7伏和+3伏是两个截然相反的脉冲信号,足以让航天飞机掉进茫茫大海了……

还是以 (-7)%10 为例。同余定理是数学的基础定理之一,中学生都懂,我们来看看:

13 %10 = 3
(13+10)%10= 3
(13+20)%10= 3
(13-10)%10= 3
(13-20)%10=(-7)%10=? —— 问题来了。

显然,根据余数定理,答案无疑就是+3 ,而不是 -7 。这与我的上述观点互相印证。

如果认为 (-7)%10=-7 的话,那么连中学生都懂的余数定理就不成立了,数学变得如此脆弱,如此不堪一击。

余数定理是计算机表示负数、补数的理论基础,那些编译器产生的混乱结果,恰恰说明这些编译器的开发者不懂得余数的概念和意义。毕竟,搞电脑和搞数学是不同的领域。
<think>好的,我现在需要回答用户关于“qt ”的问题。用户之前已经问过关于QScrollArea设置滚动条策略的问题,现在转向了Qt中的操作。首先,我要确认用户的问题具体是什么。 “”通常指的是求两个数相除后的余数,也就是模运算。在编程中,不同的语言对负数的处理方式可能不同,所以用户可能想知道Qt中如何处理运算,尤其是涉及到负数的情况。Qt是基于C++的框架,所以首先需要考虑C++中的运算符,以及Qt是否提供了相关的函数。 首先,C++中的运算符是%。例如,5 % 2的结果是1,-5 % 2在C++中通常是-1,但具体行为可能依赖于编译器。不过,用户可能关心的是在Qt中是否有不同于标准C++的处理方式,或者是否有Qt特定的函数来处理运算,特别是当处理负数时,或者是否有数学函数库中的方法。 接下来,我需要回忆Qt的文档中是否有相关的函数。Qt核心模块主要关注GUI和基础工具,数学运算通常依赖于C++标准库。不过,Qt可能在一些类中提供了额外的数学函数,比如QPoint、QRect等几何类,或者Qt Math模块是否有相关的内容。另外,Qt的QML部分是否有不同的处理方式,但用户的问题可能更偏向C++层面。 需要确认的是,在Qt中,操作是否与C++一致,或者是否有推荐的做法。例如,处理负数时,可能需要确保余数的符号与被除数或除数一致,这时候可能需要自己实现函数,或者使用标准库中的函数。 此外,用户可能对模的区别有疑问,因为在数学上,模在处理负数时可能不同。例如,-5除以2的余数在数学上可能是1(如果商向无穷整),而C++的%运算符可能返回-1(如果商向零整)。这时候用户可能需要一个始终返回非余数的函数,或者符合特定数学定义的函数。 因此,在回答中需要涵盖以下几点: 1. Qt中的基本方法,即使用%运算符。 2. 解释C++中%运算符的行为,特别是在处理负数时的表现。 3. 提及Qt是否有提供额外的函数来处理不同的需求,比如qFloor或qCeil等辅助函数,或者如何结合这些函数来实现不同的逻辑。 4. 提供示例代码,展示在不同情况下的使用方法和结果。 5. 可能的注意事项,如处理负数时的结果差异,以及如何确保余数的符号符合预期。 需要验证这些信息是否正确。查阅Qt文档,确认Qt是否引入了自己的函数。例如,在Qt Core模块中,可能没有特定的函数,但可能使用了C++的数学库中的函数。同时,检查C++标准中%运算符的定义,确认其行为,特别是在C++11及之后的标准中,规定当商向零整时,余数的符号与被除数相同。例如,-5 % 2在C++中结果为-1,而5 % -2结果为1。这可能导致在某些应用中需要调整余数为非负数,例如使用((a % b) + b) % b这样的表达式。 此外,Qt可能在某些上下文中处理,比如在信号槽的参数传递中,但用户的问题更可能关注于数值运算本身。因此,重点应放在C++的%运算符和可能的辅助方法上。 总结回答的结构: - 介绍在Qt中的基本使用(%运算符)。 - 解释C++中%的行为,特别是负数情况。 - 讨论如何根据需求调整余数的处理。 - 提供示例代码。 - 可能的注意事项或最佳实践。 需要确保回答准确,避免错误,例如不要混淆模的区别,或者错误地引用Qt不存在的函数。同时,使用用户之前接受的格式,如分点说明、代码示例等,保持结构清晰。</think>--- 在 Qt 中实现**运算**(即求模运算)时,核心方法与标准 C++ 一致,但需注意**负数处理**的细节。以下是详细解析: --- ### 1. **基础方法:使用 `%` 运算符** Qt/C++ 中直接使用 `%` 运算符进行: ```cpp int result = a % b; // 计算 a 除以 b 的余数 ``` - **示例**: ```cpp qDebug() << 7 % 3; // 输出 1 qDebug() << -7 % 3; // 输出 -1(余数符号与被除数一致) qDebug() << 7 % -3; // 输出 1(余数符号与被除数一致) ``` --- ### 2. **关键行为:负数规则** - **符号规则**:余数的符号**始终与被除数相同**(C++11 标准规定)。 ```cpp -7 % 3 = -1 // 被除数为余数 7 % -3 = 1 // 被除数为正,余数为正 ``` - **数学定义**:满足公式 $a = b \times q + r$,其中 $q$ 是商(向零整)。 --- ### 3. **常见需求:非余数** 若需余数始终在 $[0, b)$ 范围内(例如密码学、循环索引),需手动调整: ```cpp int mod(int a, int b) { int r = a % b; return r < 0 ? r + b : r; } ``` - **示例**: ```cpp qDebug() << mod(-7, 3); // 输出 2(而非 -1) ``` --- ### 4. **Qt 辅助函数** Qt 未直接提供函数,但可通过以下工具简化计算: - **`qFloor` / `qCeil`**:结合浮点运算调整余数方向: ```cpp double a = -7.5; double floorRemainder = a - qFloor(a / 3.0) * 3.0; // 结果为 1.5 ``` --- ### 5. **实际应用场景** - **循环列表索引**: ```cpp int index = -1; int safeIndex = mod(index, list.size()); // 确保索引非 ``` - **时间周期计算**(如时钟): ```cpp int hours = (currentHour + offset) % 24; // 24小时制循环 ``` --- ### 6. **注意事项** - **除数不能为 0**:需提前检查 `b != 0`,否则触发未定义行为。 - **浮点数**:使用 `std::fmod`(需包含 `<cmath>`): ```cpp #include <cmath> double result = std::fmod(7.5, 3.0); // 输出 1.5 ``` --- 通过合理选择策略,可以确保代码在不同场景下(尤其是涉及负数时)的行为符合预期。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值