fixed some issues on negative division/modulo.

This commit is contained in:
Kang Seonghoon 2014-03-31 14:33:47 +09:00
parent c9ec9ee63f
commit 75c21b0c3e
4 changed files with 26 additions and 33 deletions

View File

@ -3,6 +3,7 @@
*/ */
use std::fmt; use std::fmt;
use num::Integer;
use duration::Duration; use duration::Duration;
use self::internals::{DateImpl, Of, Mdf, YearFlags}; use self::internals::{DateImpl, Of, Mdf, YearFlags};
@ -381,16 +382,11 @@ impl Add<Duration,DateZ> for DateZ {
// TODO overflow // TODO overflow
let year = self.year(); let year = self.year();
let mut year_div_400 = year / 400; let (mut year_div_400, year_mod_400) = year.div_mod_floor(&400);
let year_mod_400 = (year % 400) as uint; let cycle = internals::yo_to_cycle(year_mod_400 as uint, self.of().ordinal()) as int;
let mut cycle = internals::yo_to_cycle(year_mod_400, self.of().ordinal()) as int; let cycle = cycle + rhs.ndays();
cycle += rhs.ndays(); let (cycle_div_400y, cycle) = cycle.div_mod_floor(&146097);
year_div_400 += cycle / 146097; year_div_400 += cycle_div_400y;
cycle %= 146097;
if cycle < 0 {
cycle += 146097;
year_div_400 -= 400;
}
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as uint); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as uint);
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as int) }; let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as int) };
@ -411,8 +407,8 @@ impl Sub<DateZ,Duration> for DateZ {
fn sub(&self, rhs: &DateZ) -> Duration { fn sub(&self, rhs: &DateZ) -> Duration {
let year1 = self.year(); let year1 = self.year();
let year2 = rhs.year(); let year2 = rhs.year();
let (year1_div_400, year1_mod_400) = (year1 / 400, year1 % 400); let (year1_div_400, year1_mod_400) = year1.div_mod_floor(&400);
let (year2_div_400, year2_mod_400) = (year2 / 400, year2 % 400); let (year2_div_400, year2_mod_400) = year2.div_mod_floor(&400);
let cycle1 = internals::yo_to_cycle(year1_mod_400 as uint, self.of().ordinal()) as int; let cycle1 = internals::yo_to_cycle(year1_mod_400 as uint, self.of().ordinal()) as int;
let cycle2 = internals::yo_to_cycle(year2_mod_400 as uint, rhs.of().ordinal()) as int; let cycle2 = internals::yo_to_cycle(year2_mod_400 as uint, rhs.of().ordinal()) as int;
Duration::days((year1_div_400 - year2_div_400) * 146097 + (cycle1 - cycle2)) Duration::days((year1_div_400 - year2_div_400) * 146097 + (cycle1 - cycle2))
@ -669,6 +665,8 @@ mod tests {
check((2014, 1, 1), Duration::days(364), (2014, 12, 31)); check((2014, 1, 1), Duration::days(364), (2014, 12, 31));
check((2014, 1, 1), Duration::days(365*4 + 1), (2018, 1, 1)); check((2014, 1, 1), Duration::days(365*4 + 1), (2018, 1, 1));
check((2014, 1, 1), Duration::days(365*400 + 97), (2414, 1, 1)); check((2014, 1, 1), Duration::days(365*400 + 97), (2414, 1, 1));
check((-7, 1, 1), Duration::days(365*12 + 3), (5, 1, 1));
} }
#[test] #[test]
@ -712,6 +710,7 @@ mod tests {
*/ */
mod internals { mod internals {
use std::{i32, num, fmt}; use std::{i32, num, fmt};
use num::Integer;
pub use super::{Weekday, Sun, Mon, Tue, Wed, Thu, Fri, Sat}; pub use super::{Weekday, Sun, Mon, Tue, Wed, Thu, Fri, Sat};
/// The internal date representation. This also includes the packed `Mdf` value. /// The internal date representation. This also includes the packed `Mdf` value.
@ -786,8 +785,7 @@ mod internals {
]; ];
pub fn cycle_to_yo(cycle: uint) -> (uint, uint) { pub fn cycle_to_yo(cycle: uint) -> (uint, uint) {
let mut year_mod_400 = cycle / 365; let (mut year_mod_400, mut ordinal0) = cycle.div_rem(&365);
let mut ordinal0 = cycle % 365;
let delta = YEAR_DELTAS[year_mod_400] as uint; let delta = YEAR_DELTAS[year_mod_400] as uint;
if ordinal0 < delta { if ordinal0 < delta {
year_mod_400 -= 1; year_mod_400 -= 1;
@ -805,8 +803,7 @@ mod internals {
impl YearFlags { impl YearFlags {
#[inline] #[inline]
pub fn from_year(year: int) -> YearFlags { pub fn from_year(year: int) -> YearFlags {
let mut year = year % 400; let year = year.mod_floor(&400);
if year < 0 { year += 400; }
unsafe { YearFlags::from_year_mod_400(year) } unsafe { YearFlags::from_year_mod_400(year) }
} }

View File

@ -3,6 +3,7 @@
*/ */
use std::{fmt, num}; use std::{fmt, num};
use num::Integer;
static NANOS_PER_SEC: int = 1_000_000_000; static NANOS_PER_SEC: int = 1_000_000_000;
static SECS_PER_DAY: int = 86400; static SECS_PER_DAY: int = 86400;
@ -16,13 +17,9 @@ pub struct Duration {
impl Duration { impl Duration {
pub fn new(days: int, secs: int, nanos: int) -> Option<Duration> { pub fn new(days: int, secs: int, nanos: int) -> Option<Duration> {
let mut secs_ = nanos / NANOS_PER_SEC; let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
let mut nanos = nanos % NANOS_PER_SEC;
if nanos < 0 { secs_ -= 1; nanos += NANOS_PER_SEC; }
let secs = match secs.checked_add(&secs_) { Some(v) => v, None => return None }; let secs = match secs.checked_add(&secs_) { Some(v) => v, None => return None };
let mut days_ = secs / SECS_PER_DAY; let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
let mut secs = secs % SECS_PER_DAY;
if secs < 0 { days_ -= 1; secs += SECS_PER_DAY; }
let days = match days.checked_add(&days_) { Some(v) => v, None => return None }; let days = match days.checked_add(&days_) { Some(v) => v, None => return None };
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
} }
@ -54,9 +51,7 @@ impl Duration {
#[inline] #[inline]
pub fn seconds(secs: int) -> Duration { pub fn seconds(secs: int) -> Duration {
let mut days = secs / SECS_PER_DAY; let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
let mut secs = secs % SECS_PER_DAY;
if secs < 0 { days -= 1; secs += SECS_PER_DAY; }
Duration { secs: secs as u32, ..Duration::days(days) } Duration { secs: secs as u32, ..Duration::days(days) }
} }
@ -72,9 +67,7 @@ impl Duration {
#[inline] #[inline]
pub fn nanoseconds(nanos: int) -> Duration { pub fn nanoseconds(nanos: int) -> Duration {
let mut secs = nanos / NANOS_PER_SEC; let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
let mut nanos = nanos % NANOS_PER_SEC;
if nanos < 0 { secs -= 1; nanos += NANOS_PER_SEC; }
Duration { nanos: nanos as u32, ..Duration::seconds(secs) } Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
} }

View File

@ -1,7 +1,9 @@
#[crate_id = "chrono#0.1.0"]; #![crate_id = "chrono#0.1.0"]
#[crate_type = "lib"]; #![crate_type = "lib"]
#[feature(globs, macro_rules)]; #![feature(globs, macro_rules)]
extern crate num;
pub mod duration; pub mod duration;
pub mod date; pub mod date;

View File

@ -3,6 +3,7 @@
*/ */
use std::fmt; use std::fmt;
use num::Integer;
use duration::Duration; use duration::Duration;
pub trait Timelike { pub trait Timelike {
@ -146,8 +147,8 @@ impl Add<Duration,TimeZ> for TimeZ {
nanos -= maxnanos; nanos -= maxnanos;
secs += 1; secs += 1;
} }
let (s, mins) = (secs % 60, secs / 60); let (mins, s) = secs.div_rem(&60);
let (m, hours) = (mins % 60, mins / 60); let (hours, m) = mins.div_rem(&60);
let h = hours % 24; let h = hours % 24;
TimeZ { hour: h as u8, min: m as u8, sec: s as u8, frac: nanos } TimeZ { hour: h as u8, min: m as u8, sec: s as u8, frac: nanos }
} }