Skip to content

Poor formatting of multiplication/division of parenthesized expression containing +/- #3552

Open
@jturner314

Description

@jturner314

When a long parenthesized expression containing addition or subtraction is followed by multiplication or division, the formatted result can be confusing. These are some examples:

fn main() {
    let dv = (2. * m * l * dtheta * dtheta * theta.sin()
        + 3. * m * g * theta.sin() * theta.cos()
        + 4. * u
        - 4. * b * v)
        / (4. * (M + m) - 3. * m * theta.cos().powi(2));
    let ddtheta = (-3. * m * l * dtheta * dtheta * theta.sin() * theta.cos()
        - 6. * (M + m) * g * theta.sin()
        - 6. * (u - b * v) * theta.cos())
        / (4. * l * (m + M) - 3. * m * l * theta.cos().powi(2));
}
fn main() {
    let V: Array2<_> = (((&lq + &vi).mapv(f64::exp) - &q) * (mi_minus_mi_t).mapv(f64::cos)
        - ((&lq - &vi).mapv(f64::exp) - &q) * (mi_plus_mi_t).mapv(f64::cos))
        * e.as_row()
        * e.as_column()
        * 0.5;
}
fn main() {
    dVdm.slice_mut(s![.., .., j]).assign(
        &(((Array2::zeros((d, d)) + u.as_column() - u.as_row()) * &U1
            + (Array2::<f64>::zeros((d, d)) + u.as_column() + u.as_row()) * &U2)
            * e.as_column()
            * e.as_row()),
    );
}
fn main() {
    {
        {
            {
                {
                    {
                        let LdXi: Array2<_> = (dmahai
                            + kdX.slice(s![.., i, d]).into_column()
                            + kdX.slice(s![.., j, d]))
                            * &L;
                    }
                }
            }
        }
    }
}

In all these examples, there is a multiplication or division of a parenthesized expression containing + or -. The * or / is indented by the same amount as the + or -, suggesting that it's at the same level, which by order of operations would mean that only the last expression would be multiplied/divided. It's not obvious that the + or - are in fact inside a parenthesized expression.

A relatively small change that would help would be to increase the indentation of the expressions inside the parentheses, like this:

fn main() {
    let dv = (2. * m * l * dtheta * dtheta * theta.sin()
            + 3. * m * g * theta.sin() * theta.cos()
            + 4. * u
            - 4. * b * v)
        / (4. * (M + m) - 3. * m * theta.cos().powi(2));
    let ddtheta = (-3. * m * l * dtheta * dtheta * theta.sin() * theta.cos()
            - 6. * (M + m) * g * theta.sin()
            - 6. * (u - b * v) * theta.cos())
        / (4. * l * (m + M) - 3. * m * l * theta.cos().powi(2));
}
fn main() {
    let V: Array2<_> = (((&lq + &vi).mapv(f64::exp) - &q) * (mi_minus_mi_t).mapv(f64::cos)
            - ((&lq - &vi).mapv(f64::exp) - &q) * (mi_plus_mi_t).mapv(f64::cos))
        * e.as_row()
        * e.as_column()
        * 0.5;
}
fn main() {
    dVdm.slice_mut(s![.., .., j]).assign(
        &(((Array2::zeros((d, d)) + u.as_column() - u.as_row()) * &U1
                + (Array2::<f64>::zeros((d, d)) + u.as_column() + u.as_row()) * &U2)
            * e.as_column()
            * e.as_row()),
    );
}
fn main() {
    {
        {
            {
                {
                    {
                        let LdXi: Array2<_> = (dmahai
                                + kdX.slice(s![.., i, d]).into_column()
                                + kdX.slice(s![.., j, d]))
                            * &L;
                    }
                }
            }
        }
    }
}

I think a better solution would be to make the parentheses more obvious by adding new lines after the opening parenthesis and before the closing parenthesis, with something like this:

fn main() {
    let dv = (
            2. * m * l * dtheta * dtheta * theta.sin()
            + 3. * m * g * theta.sin() * theta.cos()
            + 4. * u
            - 4. * b * v
        ) / (4. * (M + m) - 3. * m * theta.cos().powi(2));
    let ddtheta = (
            -3. * m * l * dtheta * dtheta * theta.sin() * theta.cos()
            - 6. * (M + m) * g * theta.sin()
            - 6. * (u - b * v) * theta.cos()
        ) / (4. * l * (m + M) - 3. * m * l * theta.cos().powi(2));
}
fn main() {
    let V: Array2<_> = (
            ((&lq + &vi).mapv(f64::exp) - &q) * (mi_minus_mi_t).mapv(f64::cos)
            - ((&lq - &vi).mapv(f64::exp) - &q) * (mi_plus_mi_t).mapv(f64::cos)
        )
        * e.as_row()
        * e.as_column()
        * 0.5;
}
fn main() {
    dVdm.slice_mut(s![.., .., j]).assign(&(
        (
            (Array2::zeros((d, d)) + u.as_column() - u.as_row()) * &U1
            + (Array2::<f64>::zeros((d, d)) + u.as_column() + u.as_row()) * &U2
        )
        * e.as_column()
        * e.as_row()
    ));
}
fn main() {
    {
        {
            {
                {
                    {
                        let LdXi: Array2<_> = (
                            dmahai
                            + kdX.slice(s![.., i, d]).into_column()
                            + kdX.slice(s![.., j, d])
                        ) * &L;
                    }
                }
            }
        }
    }
}

Although doing so is not necessary for clarity, if the closing parenthesis is moved to a new line, we could eliminate some of the extra new lines, so the middle examples would become this:

fn main() {
    let V: Array2<_> = (
            ((&lq + &vi).mapv(f64::exp) - &q) * (mi_minus_mi_t).mapv(f64::cos)
            - ((&lq - &vi).mapv(f64::exp) - &q) * (mi_plus_mi_t).mapv(f64::cos)
        )
        * e.as_row() * e.as_column() * 0.5;
}
fn main() {
    dVdm.slice_mut(s![.., .., j]).assign(&(
        (
            (Array2::zeros((d, d)) + u.as_column() - u.as_row()) * &U1
            + (Array2::<f64>::zeros((d, d)) + u.as_column() + u.as_row()) * &U2
        )
        * e.as_column() * e.as_row()
    ));
}

or this:

fn main() {
    let V: Array2<_> = (
            ((&lq + &vi).mapv(f64::exp) - &q) * (mi_minus_mi_t).mapv(f64::cos)
            - ((&lq - &vi).mapv(f64::exp) - &q) * (mi_plus_mi_t).mapv(f64::cos)
        ) * e.as_row() * e.as_column() * 0.5;
}
fn main() {
    dVdm.slice_mut(s![.., .., j]).assign(&(
        (
            (Array2::zeros((d, d)) + u.as_column() - u.as_row()) * &U1
            + (Array2::<f64>::zeros((d, d)) + u.as_column() + u.as_row()) * &U2
        ) * e.as_column() * e.as_row()
    ));
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions