Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a built-in function that converts a number to a string in any base?

Tags:

format

rust

I want to replace the inner match statement and work for all values up to when the alphabet runs out. I know I can write it myself, but I want to use built-in functions.

fn convert(inp: u32, out: u32, numb: &String) -> Result<String, String> {
    match isize::from_str_radix(numb, inp) {
        Ok(a) => match out {
            2 => Ok(format!("{:b}", a)),
            8 => Ok(format!("{:o}", a)),
            16 => Ok(format!("{:x}", a)),
            10 => Ok(format!("{}", a)),
            0 | 1 => Err(format!("No base lower than 2!")),
            _ => Err(format!("printing in this base is not supported")),
        },
        Err(e) => Err(format!(
            "Could not convert {} to a number in base {}.\n{:?}\n",
            numb, inp, e
        )),
    }
}
like image 386
Meltinglava Avatar asked May 10 '18 16:05

Meltinglava


People also ask

What function converts a number to a string?

The toString() method is a built-in method of the JavaScript Number object that allows you to convert any number type value into its string type representation.

Which built-in function converts integer value to string?

The tostring() function is used to convert an integer to string & vice-versa.

How do you convert a number from any base to any base?

Decimal to Other Base SystemStep 1 − Divide the decimal number to be converted by the value of the new base. Step 2 − Get the remainder from Step 1 as the rightmost digit (least significant digit) of new base number. Step 3 − Divide the quotient of the previous divide by the new base.

What method converts numeric values into string values?

The valueOf method in Java can be used to convert an integer to a String. It accepts one parameter, the integer value. If the value being converted is an integer, the input value MUST be an integer!


2 Answers

For now, you cannot do it using the standard library, but you can:

  • use my crate radix_fmt
  • or roll your own implementation:

    fn format_radix(mut x: u32, radix: u32) -> String {
        let mut result = vec![];
    
        loop {
            let m = x % radix;
            x = x / radix;
    
            // will panic if you use a bad radix (< 2 or > 36).
            result.push(std::char::from_digit(m, radix).unwrap());
            if x == 0 {
                break;
            }
        }
        result.into_iter().rev().collect()
    }
    
    fn main() {
        assert_eq!(format_radix(1234, 10), "1234");
        assert_eq!(format_radix(1000, 10), "1000");
        assert_eq!(format_radix(0, 10), "0");
    }
    
like image 121
Boiethios Avatar answered Sep 22 '22 16:09

Boiethios


If you wanted to eke out a little more performance, you can create a struct and implement Display or Debug for it. This avoids allocating a String. For maximum over-engineering, you can also have a stack-allocated array instead of the Vec.

Here is Boiethios' answer with these changes applied:

struct Radix {
    x: i32,
    radix: u32,
}

impl Radix {
    fn new(x: i32, radix: u32) -> Result<Self, &'static str> {
        if radix < 2 || radix > 36 {
            Err("Unnsupported radix")
        } else {
            Ok(Self { x, radix })
        }
    }
}

use std::fmt;

impl fmt::Display for Radix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut x = self.x;
        // Good for binary formatting of `u128`s
        let mut result = ['\0'; 128];
        let mut used = 0;
        let negative = x < 0;
        if negative {
            x*=-1;
        }
        let mut x = x as u32;
        loop {
            let m = x % self.radix;
            x /= self.radix;

            result[used] = std::char::from_digit(m, self.radix).unwrap();
            used += 1;

            if x == 0 {
                break;
            }
        }

        if negative {
            write!(f, "-")?;
        }

        for c in result[..used].iter().rev() {
            write!(f, "{}", c)?;
        }

        Ok(())
    }
}

fn main() {
    assert_eq!(Radix::new(1234, 10).to_string(), "1234");
    assert_eq!(Radix::new(1000, 10).to_string(), "1000");
    assert_eq!(Radix::new(0, 10).to_string(), "0");
}

This could still be optimized by:

  • creating an ASCII array instead of a char array
  • not zero-initializing the array

Since these avenues require unsafe or an external crate like arraybuf, I have not included them. You can see sample code in internal implementation details of the standard library.

like image 24
Shepmaster Avatar answered Sep 19 '22 16:09

Shepmaster