【问题标题】:Results of simple division change with a negative dividend带负股利的简单除法变化结果
【发布时间】:2013-06-26 23:40:13
【问题描述】:

s 为正时,从秒 (s) 计算分钟 (m) 和小时 (h) 可以正常工作:

s = 14200
h = s/3600 #=> 3
m = (s % 3600 ) / 60 #=> 56

但是,如果s 是负数,我会得到不同的结果:

s = -14200
h = s/3600 #=> -4
m = (s % 3600 ) / 60 #=> 3

我不明白为什么当我以相同的秒数开始时会得到 -4 小时 3 分钟,只是负数。

这里发生了什么?有什么方法可以让我获得一致的正负值结果?除了使用s.abs % 3600 并在s 为负数时修改结果吗?

【问题讨论】:

    标签: ruby division negative-number


    【解决方案1】:

    你可以想象 ruby​​ 中的整数除法是这样实现的 --

    给定ab,ruby 找到q b + m = a 的整数解,这样

    1. mb 的符号相同
    2. m 的值尽可能小(接近于零)。

    这两条规则为您提供q (a / b) 和m (a % b) 的独特解决方案。

    在您的第一种情况下,a 是 14200,b 是 3600。遵循这些规则的 q b + m = a 的唯一解是 q = 3m = 1600——试试吧。

    > 3 * 3600 + 1600
    # => 12400
    

    这是唯一的解决方案吗? q = 4 呢?那么

    4 * 3600 + m = 12400
    m = -2000
    

    不……m 现在不仅比以前更大,而且甚至是错误的符号(还记得第一条规则吗?)

    q = 2 呢?

    2 * 3600 + m = 12400
    m = 5200
    

    不...我们为m 提供的第一个解决方案更小。因此,qm 的唯一可能值是 3 和 1600。

    现在让我们试试你的第二种情况——a-12400b3600。唯一的解决方案是q = -4b = 2000

    让我们检查一下。

    > -4 * 3600 + 2000
    # => -12400
    

    有效!

    让我们快速检查q 的其他值——让我们试试 -3,如果我们与第一个示例相比,“显而易见”的答案:

    -3 * 3600 + m = -12400
    m = -1600
    

    好的...好吧,m 这里比以前“更小”了...所以它符合规则 #2。但是规则 #1 说 m 必须与 b 具有相同的符号......所以我们不会接受 m 的负值。

    因此,唯一独特的解决方案是q = -4m = 2000

    您问题中的其他两个部门应该从这里清楚。

    为了获得您预期的结果,您应该使用-3600 而不是3600 作为您的小时分红。

    【讨论】:

      【解决方案2】:

      14200 除以 3600 大约是 3.9,在整数算术中被截断为 3。

      -14200 除以 3600 大约是 -3.9,在整数运算中被截断为 -4。

      对于%,负数从第二个值开始“倒数”——当您牢记这一点时,您的结果将非常有意义。例如:

       1 % 6 # => 1
      -1 % 6 # => 5
      

      更新:如果秒数为负数,我认为您需要准确考虑您想要什么。你可以这样做:

      dir = "from now"
      
      if s < 0
        dir = "ago"
        s = -s
      end
      
      h = s / 3600
      m = (s % 3600 ) / 60
      
      puts "s represents #{h} hours and #{m} minutes #{dir}"
      

      真正要做什么取决于hm 在代码的更大上下文中的确切含义,以及负s 值在该上下文中的确切含义。

      在另一种情况下,也许您希望hm 具有相同的绝对值,就像s 为正但与s 具有相同的符号:

      sign = s < 0 ? -1 : 1
      s = s.abs
      
      h = s / 3600 * sign
      m = (s % 3600 ) / 60 * sign
      

      由您决定适合您的情况。

      【讨论】:

      • 它们对我们有意义,而不是对 OP。 :-)
      • @theTinMan 好的,稍微改写一下。我希望当他们考虑 % 对负值的含义时,结果对 OP 有意义,并且“倒数”似乎是一个很好的心理模型。
      • 现在我明白为什么了。有什么方法可以让正值和负值得到一致的结果?除了使用 s.abs % 3600 并在 s 为负数时修改结果吗?毕竟,-14200 秒仍然是负 3 小时 56 分钟,而不是负 4 小时 3 分钟。
      • @aaandre 调用abs 或以其他方式否定s 的负值对我来说似乎是正确的数学方法。适当的操作取决于您的需要,并且很难从提供的信息中判断。 (请参阅我的更新答案。)
      • 感谢您的直截了当的解释和代码示例!我的代码最终与上一个几乎相同。
      【解决方案3】:

      必须注意% 和负数。他们很狡猾:

      irb(主):011:0> 14200 % 3600 => 3400 irb(主):012:0> -14200 % 3600 => 200

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-22
        • 1970-01-01
        • 1970-01-01
        • 2017-01-11
        相关资源
        最近更新 更多