银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
  268 随笔 :: 2 文章 :: 2616 评论 :: 140万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
谜题01: 奇数性
    下面方法的目的是确定其唯一的参数是否为奇数。这个方法可行吗?
    public static bool IsOdd(int i)
    {
      return i % 2 == 1;
    }
   
解惑01: 奇数性
    奇数可定义为被2整除余数为1的整数。表达式i%2计算的是i除以2时所产生的余数,因此看起来这个程序应该可行。遗憾的是,它不行;在四分之一的时间里它返回的都是错误的答案。
    为什么是四分之一?因为在所有的int数值中,有一半是负数,而IsOdd方法对所有负奇数的判断都会失败。在任何负整数上调用该方法都会返回false,无论该整数是偶数还是奇数。
    这是C#对取余操作符(%)的定义所产生的后果。该操作符被定义为对所有的int数值a和所有的非零int数值b,都满足下面的恒等式:
    (a / b) * b + (a % b) == a
    换句话说,如果用b整除a,将商乘以b,然后加上余数,那么就得到了最初的值a[C#语言规范 7.7.3]。该恒等式具有正确的含义,但是当与C#的截尾整数整除操作符[C#语言规范 7.7.2]相结合时,它就意味着:当取余操作返回一个非零的结果时,它与左操作数具有相同的正负符号。
    IsOdd方法以及它所基于的对术语“奇数”的定义都假设所有的余数都是正数。虽然该假设对某些种类的整除是有意义的,但是C#的取余操作是与舍弃整除结果小数部分的整数整除操作完全匹配的。
    当i是一个负奇数时,i % 2等于-1而不是1,因此IsOdd方法错误地返回false。为了防止这种意外,请测试你的方法在为每一个数值型参数传递负数、零和正数数值时,其行为是否正确。
    这个问题很容易改正。只需将i % 2与0而不是与1比较,并且使用相反的比较含义即可:
    public static bool IsOdd(int i)
    {
      return i % 2 != 0;
    }
    如果正在一个强调性能的环境中使用IsOdd方法,那么用位操作符AND(&)替代取余操作符会显得更好:
    public static bool IsOdd(int i)
    {
      return (i & 1) != 0;
    }
    第二个版本运行起来可能比第一个版本要快得多,这取决于你使用的是什么样的平台和虚拟机,并且不太可能出现运行得更慢的情况。按常规来说,整除和取余操作与其他的算术和逻辑操作相比要慢一些。仓促地优化是不好的,但是在上述情况下,更快的版本与最初的版本一样清晰明白,所以没有任何理由偏爱最初的版本。
    总之,无论何时使用了取余操作符,都要考虑操作数和结果的符号。该操作符的行为在其操作数非负时是一目了然的,但是当一个或两个操作数是负数时,它的行为就不那么显而易见了。

    C#解惑总目录
posted on   银河  阅读(1542)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示