Question

Calculating minutes (m) and hours (h) from seconds (s) works as I expect when s is positive:

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

However, if s is a negative number, I get different results:

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

I don't understand why I get -4 hours and 3 minutes when I start with the same number of seconds, just negative.

What is going on here? And is there any way I can get consistent results for positive and negative values? Beyond using s.abs % 3600 and modifying the results if s was negative?

Était-ce utile?

La solution 2

14200 divided by 3600 is approximately 3.9, which in integer arithmetic is truncated to 3.

-14200 divided by 3600 is approximately -3.9, which in integer arithmetic is truncated to -4.

With %, negatives "count backward" from the second value -- your results make perfect sense when you keep that in mind. For example:

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

Update: I think you need to think about exactly what you want if the seconds are negative. You might do something like this:

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}"

What to do really depends on exactly what h and m mean in the greater context of your code, and exactly what negative s values mean in that context.

In another situation, maybe you want h and m to have the same absolute value as if s was positive but with the same sign as s:

sign = s < 0 ? -1 : 1
s = s.abs

h = s / 3600 * sign
m = (s % 3600 ) / 60 * sign

It's up to you to determine what is appropriate in your situation.

Autres conseils

You can think of integer division in ruby implemented like this --

given a and b, ruby finds integer solutions to q b + m = a such that

  1. m is the same sign as b
  2. the value of m is made as small (close to zero) as possible.

These two rules give you unique solutions for q (a / b) and m (a % b).

in your first case, a is 14200 and b is 3600. The unique solutions of q b + m = a that follow those rules is q = 3 and m = 1600 -- try it.

> 3 * 3600 + 1600
# => 12400

Is this the only solution? What about q = 4? then

4 * 3600 + m = 12400
m = -2000

nope ... not only is m now bigger than before, but it's even the wrong sign (remember the first rule?)

What about q = 2 ?

2 * 3600 + m = 12400
m = 5200

nope ... our first solution for m was smaller. Therefore the only values of q and m possible are 3 and 1600.

Now let's try your second case -- a is -12400 and b is 3600 again. The unique solution is q = -4 and b = 2000.

Let's check.

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

it works!

let's quickly check other values of q -- let's try -3, the "obvious" answer if we compare to the first example:

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

okay...well, m here is "smaller" than before...so it fits Rule #2. But rule #1 says that m has to be the same sign as b...so we won't accept negative values of m.

Therefore the only unique solutions are q = -4 and m = 2000.

The other two divisions then in your question should be clear from here.

In order to get the results you seem to expect, you should use -3600 instead of 3600 for your hour dividend.

Gotta watch out for % and negative numbers. They're tricksy:

irb(main):011:0> 14200 % 3600
=> 3400
irb(main):012:0> -14200 % 3600
=> 200
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top