Is there a way to convert a `String` to `u64` and trim any floating points?

Let's say that I'm having the following String: "10.20"

Is there a way to convert it to u64 and trim the decimal point so I can get the result: 10?

Or should I do it manually?

I would recommand you to specify precisely what the domain of input is and what the output should be. A restricted domain of input should have its own data type. Otherwise it should be made clear what happens in case of failure.

use std::num::ParseIntError;

fn integer_part(value: &str) -> Result<u64, ParseIntError> {
    let dot_pos = value.find(".").unwrap_or(value.len());
    value[..dot_pos].parse()
}
9 Likes

Another option might be:

fn integer_part(repr: &str) -> Result<u64, ()> {
    match repr.split('.').next() {
        Some(x) => x.parse().map_err(|_| ()),
        None => Err(())
    }
}

Edit: It seems, one can do this:

use std::num::ParseIntError;

fn integer_part(repr: &str) -> Result<u64, ParseIntError> {
    match repr.split('.').next() {
        Some(x) => x.parse(),
        None => unreachable!()
    }
}
1 Like

fixed as @H2CO3 recommonded:

    let str="-10.20".to_string();
    let integer=str.split('.').next();
    let n = match integer {
        Some(num)=>match num.parse::<u64>() {
            Ok(num)=>num,
            Err(_)=>panic!("Err: Cannot Parse The Integer."),
        },
        None=>panic!("Err: Cannot Parse The String."),
    };
    assert_eq!(10,n);
3 Likes

Casting a f64 to a u64 loses information. Don't try to first parse as a floating-point number and then truncate. The other answers show how it can be done more robustly by first finding the decimal point and then parsing to the correct type to begin with.

2 Likes

Don't worry, I handle errors. The string will ALWAYS be a number. Either and integer or a float

When saying information, I hope you mean precision, right? If that's the case, then in my problem, I don't need the floating points...

@alice @Finn @42Surtr All your solutions work great, except that they don't check if they don't handle negative numbers but I don't need that in my problem so everything is fine! Thanks a lot everyone for your time and I wish you all to have an amazing day!

No. Precision is not the same as "fractional part", and fractional part is not the same as significant digits. Floating-point numbers of a certian bit width can't represent all integers of the same bit width. For example, f64 can only accurately hold integers up to 2^53 or something like that; above that, only even integers can be represented, then an order of magnitude later, only integers divisible by 4, etc. This means that you must deal with this problem even if you don't need the fractional part.

3 Likes

Hmmm. I don't think that my users will ever have this problem (I'm making a program similar to sleep) so probably no one will ever enter 18,446,744,073,709,551,615. From what I was able to found, even nanoseconds is one billionth of the second so even this super height rescission so you can play with billions of nanoseconds (If I understand it right). Now if something needs something even more special, they are free to make their own program, I'll just make sure to leave a note to mine. Thanks a lot for your time

But could they enter ”1.0e1”?

They won't. The argument is spitted into the duration and the suffix which tells the precision. "1.0e1" will be parsed as "1.0" (which will get trimmed to "1") for the duration and "e1" for the suffix (which is not an accepted suffix). So we're safe :wink:

So, 1.0e1 would be treated as 1 and not 10?

Yes! The floating points will get trimmed.

But in this case this is not a "trimming" - the value you use isn't the value they input, even rounded.

1 Like

Hmmm. I mean, I don't know how to call it but this is the behavior. If needed, one can use another tool to first convert the number to an integer and then use it. This program should not be a convertor. Remember, do one things and do it good.

A program that turns 1.0e10 into 1 silently, without issuing an error is not "doing one thing well". Why even allow fractional parts if you're going to ignore them? As you say, "one can use another tool to first convert the number to an integer and then use it." So why are you going out of your way to incorrectly convert floating-point numbers to integers? Just call parse().unwrap() and then at least the person who writes 0.5 will get a nice error message that says the value provided was not an integer instead of just getting incorrect results.

Don't check for errors if you know you can't handle them gracefully.

13 Likes

I see a few replies that suggest to split on the dot character; I would be wary of that if you need to support multiple locales: numbers formatting is not the same everywhere and is not that simple.

Do you really need to parse formatted numbers? If that is the case, maybe try and find a lib dedicated to that, that can handle the localisation if necessary.

If you are fine with accepting only formats handled by Rust's float parsing, then you could parse to float, though I wouldn't do it if I was actually needing an integer.

If you need your user to provide an integer input… then do not accept anything that is not representing an integer. Otherwise it might be confusing to the user. Trimming whitespaces is acceptable because it is most probably not purposely provided by the user. But if they make the choice to provide a decimal part and that you cannot use it, they should know.

5 Likes

Actually you are totally right and I'm going to not accept floating point numbers! You see my idea was like if people entered something like "10.7", I would just trim it for them to just save them some time but I shouldn't suppose that they'll want this behavior. Maybe someone expects 10.7 seconds and doesn't know how the program works and I should just let them know and point them to get help. Thanks a lot for the recommendation!