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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
The commit information below represents what I submitted to upstream
in a pull request at debian/patches/replace-floating-point-with-integer.patch
the actual patch in this file differs slightly because of adaptations needed
to suit the version of the pacakge in Debian.
commit f5ed7667eb7639a480390d728153782119244bb1
Author: Peter Michael Green <plugwash@debian.org>
Date: Sat Aug 21 20:53:05 2021 +0000
Replace rounding-error prone floating point code with robust integer code.
Index: iso8601/src/parsers.rs
===================================================================
--- iso8601.orig/src/parsers.rs
+++ iso8601/src/parsers.rs
@@ -101,14 +101,6 @@ fn sign(i: &[u8]) -> IResult<&[u8], i32>
})(i)
}
-fn fractions(i: &[u8]) -> IResult<&[u8], f32> {
- let (i, digits) = take_while(is_digit)(i)?;
- let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
- let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.
-
- Ok((i, f))
-}
-
// DATE
// [+/-]YYYY
@@ -204,8 +196,25 @@ fn time_second(i: &[u8]) -> IResult<&[u8
n_digit_in_range(i, 2, 0..=60)
}
-fn time_millisecond(fraction: f32) -> u32 {
- (1000.0 * fraction) as u32
+fn time_millisecond(i: &[u8]) -> IResult<&[u8], u32> {
+ let (i, mut digits) = take_while(is_digit)(i)?;
+ let mut l = digits.len();
+ if l > 3 {
+ digits = digits.get(0..3).unwrap();
+ }
+ let mut result = 0;
+ if l > 0 {
+ let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
+ result = digits.parse().unwrap();
+ }
+ while l < 3 {
+ result = result * 10;
+ l += 1;
+ }
+ //let fraction: f32 = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.
+
+ //let result = (1000.0 * fraction) as u32;
+ Ok ((i,result))
}
// HH:MM:[SS][.(m*)][(Z|+...|-...)]
@@ -216,7 +225,7 @@ pub fn parse_time(i: &[u8]) -> IResult<&
opt(tag(b":")), // :
time_minute, // MM
opt(preceded(opt(tag(b":")), time_second)), // [SS]
- opt(map(preceded(one_of(",."), fractions), time_millisecond)), // [.(m*)]
+ opt(preceded(one_of(",."), time_millisecond)), // [.(m*)]
opt(alt((timezone_hour, timezone_utc))), // [(Z|+...|-...)]
)),
|(h, _, m, s, ms, z)| {
@@ -288,13 +297,30 @@ fn duration_minute(i: &[u8]) -> IResult<
// S[S][[,.][MS]]
fn duration_second_and_millisecond(i: &[u8]) -> IResult<&[u8], (u32, u32)> {
let (i, s) = m_to_n_digit_in_range(i, 1, 2, 0..=60)?;
- let (i, ms) = opt(map(preceded(one_of(",."), fractions), duration_millisecond))(i)?;
+ let (i, ms) = opt(preceded(one_of(",."), duration_millisecond))(i)?;
Ok((i, (s, ms.unwrap_or(0))))
}
-fn duration_millisecond(fraction: f32) -> u32 {
- (1000.0 * fraction) as u32
+fn duration_millisecond(i: &[u8]) -> IResult<&[u8], u32> {
+ let (i, mut digits) = take_while(is_digit)(i)?;
+ let mut l = digits.len();
+ if l > 3 {
+ digits = digits.get(0..3).unwrap();
+ }
+ let mut result = 0;
+ if l > 0 {
+ let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
+ result = digits.parse().unwrap();
+ }
+ while l < 3 {
+ result = result * 10;
+ l += 1;
+ }
+ //let fraction: f32 = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.
+
+ //let result = (1000.0 * fraction) as u32;
+ Ok ((i,result))
}
fn duration_time(i: &[u8]) -> IResult<&[u8], (u32, u32, u32, u32)> {
Index: iso8601/tests/lib.rs
===================================================================
--- iso8601.orig/tests/lib.rs
+++ iso8601/tests/lib.rs
@@ -22,6 +22,21 @@ fn test_date() {
#[test]
fn test_millisecond() {
+ let mut i=0;
+ while i < 1000 {
+ assert_eq!(
+ Ok(Time {
+ hour: 16,
+ minute: 43,
+ second: 0,
+ millisecond: i,
+ tz_offset_hours: 0,
+ tz_offset_minutes: 0
+ }),
+ time(format!("16:43:00.{:0>3}",i).as_str())
+ );
+ i+=1;
+ }
assert_eq!(
Ok(Time {
hour: 16,
|