[solved] Macros: if in const assignments


#1

I’m newbe in rust. My training project is a fixedpoint arithmetic package for rust. For this, I need a macro to convert from float to u32. I managed the following code to compile:

const ONE: i32 = 1 << 16;

macro_rules! rconst {
    ($x:expr) => {
        ($x * ONE as f32) as i32
    };
}

const PI: i32 = rconst!(3.14);

fn main() {
    println!("{:?}", PI);
    
}

This works and that is fine. Better would be, to half ther rounding errors. In C the macro looks like this:

#define rconst(R) ((fixedpt)((R) * FIXEDPT_ONE + ((R) >= 0 ? 0.5 : -0.5)))

How can I do this with a rust macro?

Thanks
Simsys


#2

Rust doesn’t have the ternary operator. Instead, regular if is just an expression.

Unfortunately, it can’t currently evaluate ifs in const contexts. So you can’t do this… directly.

What you can do is abuse arithmetic shift rules:

const ONE: i32 = 1 << 16;

macro_rules! rconst {
    ($x:expr) => {
        (
            $x
            * (ONE as f32)
            + ((((($x * (ONE as f32)) as i32) >> 31) as f32) + 0.5)
        ) as i32
    };
}

const PI: i32 = rconst!(3.14);
const NOT_PI: i32 = rconst!(-1.23);

fn main() {
    println!("{:?}", PI as f32 / ONE as f32);
    println!("{:?}", NOT_PI as f32 / ONE as f32);
}

Just be aware: every time I tried to add rconst!(0.0), the playpen timed out… dunno what’s up with that.


#3

Thank You very much for this solution.


#4

It’s much simpler to use an array of two elements:

const CHOICE1: &'static str = "True";
const CHOICE2: &'static str = "False";

const NEG_CONDITION: usize = 0;

const SELECTED: &'static str = [CHOICE1, CHOICE2][NEG_CONDITION];

fn main() {
    println!("{}", SELECTED);
}

#5

Except you’d still have to get 0/1 without using if… which would be (((($x * (ONE as f32)) as i32) >> 31) + 1) as usize in this case, and how is that any simpler? :stuck_out_tongue: