Skip to content

Complex remainder doesn't find the nearest multiplicator of the divider due to approximations #445

@Astrac

Description

@Astrac

I noticed that if I calculate cetain remainders I get results that do not agree with what I calculate using other tools; for example, 10 % (5 + 7i) gives 10 as a result with this library but other tools (e.g. wolfram alpha) give me -2 - 2i. To corroborate wolfram's result just notice that |10| = 10 and |5 + 7i| ~ 8.6, while the modulus of the reminder should be smaller than the one of the divisor.

I found that the issue causing this is the way the remainder is computed using only integer types: the implementation always find the biggest multiplier of the divisor that is smaller than dividend, not the nearest mutiplier. If I rewrite the algorithm as follows I get the very same results as wolfram and other code of mine that depends on this calculation behaves correctly:

fn calc_mod(n: Complex<i32>, modulus: Complex<i32>) -> Complex<i32> {
    // Transform to f32
    let nf = Complex::new(n.re as f32, n.im as f32);
    let modf = Complex::new(modulus.re as f32, modulus.im as f32);
    
    // The usual complex division formula but applied to Complex<f32> instead of <Complex<i32>
    let div = (nf * modf.conj()) / modf.norm_sqr();

    // use round() to ensure closest multiplier is found
    let rounded = Complex::new(div.re.round() as i32, div.im.round() as i32); 
    let nearest_mult = rounded * modulus;

    return n - nearest_mult;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions