rustinteger-overflow

My test fails at "attempt to subtract with overflow"


use itertools::Itertools;

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Runner {
    sec: u16,
}

impl Runner {
    fn from(v: (u8, u8, u8)) -> Runner {
        Runner {
            sec: v.0 as u16 * 3600 + v.1 as u16 * 60 + v.2 as u16
        }
    }
}


fn parse_runner(strg: &str) -> Vec<Runner> {
    strg.split(", ")
        .flat_map(|personal_result| personal_result.split('|'))
        .map(|x| x.parse::<u8>().unwrap())
        .tuples::<(_, _, _)>()
        .map(|x| Runner::from(x))
        .sorted()
        .collect::<Vec<Runner>>()
}

fn parse_to_format(x: u16) -> String {
    let h = x / 3600;
    let m = (x - 3600)/60;
    let s = x % 60;

    format!("{:02}|{:02}|{:02}", h, m, s)
}

fn return_stats(runners: &[Runner]) -> String {
    let range: u16 = runners.last().unwrap().sec - runners.first().unwrap().sec;
    let average: u16 = runners.iter().map(|&r| r.sec).sum::<u16>()/(runners.len() as u16);
    let median: u16 = if runners.len()%2 != 0 {
        runners.get(runners.len()/2).unwrap().sec
    } else {
        runners.get(runners.len()/2).unwrap().sec/2 + runners.get((runners.len()/2) + 1).unwrap().sec/2
    };
    format!("Range: {} Average: {} Median: {}", parse_to_format(range), parse_to_format(average), parse_to_format(median))

}

fn stati(strg: &str) -> String {
    let run_vec = parse_runner(strg);
    return_stats(&run_vec)
}

I cant find the mistake I made with supposedly substraction to make my code pass the test. Basically I'm trying to start with a &str like "01|15|59, 1|47|6, 01|17|20, 1|32|34, 2|3|17" and end up with another one like "Range: 00|47|18 Average: 01|35|15 Median: 01|32|34"

Sorry in advance for my mistake if it is really stupid, I've been trying to fix it for quite a while

https://www.codewars.com/kata/55b3425df71c1201a800009c/train/rust


Solution

  • let m = (x - 3600) / 60;
    

    As Peter mentioned, that will indeed overflow if x is less than 3600. A u16 can not be negative.

    Using integer arithmetic, here's another way of formatting seconds to hh|mm|ss and does not experience overflow:

    fn seconds_to_hhmmss(mut s: u64) -> String {
        let h = s / 3600;
        s -= h * 3600;
        let m = s / 60;
        s -= m * 60;
        
        format!("{:02}|{:02}|{:02}", h, m, s)
    }