Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  rem.rs

  Sprache: Rust
 

use crate::constants::{MAX_I32_SCALE, MAX_PRECISION_I32, POWERS_10};
use crate::decimal::{CalculationResult, Decimal};
use crate::ops::common::{Buf12, Buf16, Buf24, Dec64};

pub(cratefn rem_impl(d1: &Decimal, d2: &Decimal) -> CalculationResult {
    if d2.is_zero() {
        return CalculationResult::DivByZero;
    }
    if d1.is_zero() {
        return CalculationResult::Ok(Decimal::ZERO);
    }

    // We handle the structs a bit different here. Firstly, we ignore both the sign/scale of d2.
    // This is because during a remainder operation we do not care about the sign of the divisor
    // and only concern ourselves with that of the dividend.
    let mut d1 = Dec64::new(d1);
    let d2_scale = d2.scale();
    let mut d2 = Buf12::from_decimal(d2);

    let cmp = crate::ops::cmp::cmp_internal(
        &d1,
        &Dec64 {
            negative: d1.negative,
            scale: d2_scale,
            hi: d2.hi(),
            low64: d2.low64(),
        },
    );
    match cmp {
        core::cmp::Ordering::Equal => {
            // Same numbers meaning that remainder is zero
            return CalculationResult::Ok(Decimal::ZERO);
        }
        core::cmp::Ordering::Less => {
            // d1 < d2, e.g. 1/2. This means that the result is the value of d1
            return CalculationResult::Ok(d1.to_decimal());
        }
        core::cmp::Ordering::Greater => {}
    }

    // At this point we know that the dividend > divisor and that they are both non-zero.
    let mut scale = d1.scale as i32 - d2_scale as i32;
    if scale > 0 {
        // Scale up the divisor
        loop {
            let power = if scale >= MAX_I32_SCALE {
                POWERS_10[9]
            } else {
                POWERS_10[scale as usize]
            } as u64;

            let mut tmp = d2.lo() as u64 * power;
            d2.set_lo(tmp as u32);
            tmp >>= 32;
            tmp = tmp.wrapping_add((d2.mid() as u64 + ((d2.hi() as u64) << 32)) * power);
            d2.set_mid(tmp as u32);
            d2.set_hi((tmp >> 32as u32);

            // Keep scaling if there is more to go
            scale -= MAX_I32_SCALE;
            if scale <= 0 {
                break;
            }
        }
        scale = 0;
    }

    loop {
        // If the dividend is smaller than the divisor then try to scale that up first
        if scale < 0 {
            let mut quotient = Buf12 {
                data: [d1.lo(), d1.mid(), d1.hi],
            };
            loop {
                // Figure out how much we can scale by
                let power_scale;
                if let Some(u) = quotient.find_scale(MAX_PRECISION_I32 + scale) {
                    if u >= POWERS_10.len() {
                        power_scale = 9;
                    } else {
                        power_scale = u;
                    }
                } else {
                    return CalculationResult::Overflow;
                };
                if power_scale == 0 {
                    break;
                }
                let power = POWERS_10[power_scale] as u64;
                scale += power_scale as i32;

                let mut tmp = quotient.data[0as u64 * power;
                quotient.data[0] = tmp as u32;
                tmp >>= 32;
                quotient.set_high64(tmp.wrapping_add(quotient.high64().wrapping_mul(power)));
                if power_scale != 9 {
                    break;
                }
                if scale >= 0 {
                    break;
                }
            }
            d1.low64 = quotient.low64();
            d1.hi = quotient.data[2];
            d1.scale = d2_scale;
        }

        // if the high portion is empty then return the modulus of the bottom portion
        if d1.hi == 0 {
            d1.low64 %= d2.low64();
            return CalculationResult::Ok(d1.to_decimal());
        } else if (d2.mid() | d2.hi()) == 0 {
            let mut tmp = d1.high64();
            tmp = ((tmp % d2.lo() as u64) << 32) | (d1.lo() as u64);
            d1.low64 = tmp % d2.lo() as u64;
            d1.hi = 0;
        } else {
            // Divisor is > 32 bits
            return rem_full(&d1, &d2, scale);
        }

        if scale >= 0 {
            break;
        }
    }

    CalculationResult::Ok(d1.to_decimal())
}

fn rem_full(d1: &Dec64, d2: &Buf12, scale: i32) -> CalculationResult {
    let mut scale = scale;

    // First normalize the divisor
    let shift = if d2.hi() == 0 {
        d2.mid().leading_zeros()
    } else {
        d2.hi().leading_zeros()
    };

    let mut buffer = Buf24::zero();
    let mut overflow = 0u32;
    buffer.set_low64(d1.low64 << shift);
    buffer.set_mid64(((d1.mid() as u64).wrapping_add((d1.hi as u64) << 32)) >> (32 - shift));
    let mut upper = 3// We start at 3 due to bit shifting

    while scale < 0 {
        let power = if -scale >= MAX_I32_SCALE {
            POWERS_10[9]
        } else {
            POWERS_10[-scale as usize]
        } as u64;
        let mut tmp64 = buffer.data[0as u64 * power;
        buffer.data[0] = tmp64 as u32;

        for (index, part) in buffer.data.iter_mut().enumerate().skip(1) {
            if index > upper {
                break;
            }
            tmp64 >>= 32;
            tmp64 = tmp64.wrapping_add((*part as u64).wrapping_mul(power));
            *part = tmp64 as u32;
        }
        // If we have overflow then also process that
        if upper == 6 {
            tmp64 >>= 32;
            tmp64 = tmp64.wrapping_add((overflow as u64).wrapping_mul(power));
            overflow = tmp64 as u32;
        }

        // Make sure the high bit is not set
        if tmp64 > 0x7FFF_FFFF {
            upper += 1;
            if upper > 5 {
                overflow = (tmp64 >> 32as u32;
            } else {
                buffer.data[upper] = (tmp64 >> 32as u32;
            }
        }
        scale += MAX_I32_SCALE;
    }

    // TODO: Optimize slice logic

    let mut tmp = Buf16::zero();
    let divisor = d2.low64() << shift;
    if d2.hi() == 0 {
        // Do some division
        if upper == 6 {
            upper -= 1;

            tmp.data = [buffer.data[4], buffer.data[5], overflow, 0];
            tmp.partial_divide_64(divisor);
            buffer.data[4] = tmp.data[0];
            buffer.data[5] = tmp.data[1];
        }
        if upper == 5 {
            upper -= 1;
            tmp.data = [buffer.data[3], buffer.data[4], buffer.data[5], 0];
            tmp.partial_divide_64(divisor);
            buffer.data[3] = tmp.data[0];
            buffer.data[4] = tmp.data[1];
            buffer.data[5] = tmp.data[2];
        }
        if upper == 4 {
            tmp.data = [buffer.data[2], buffer.data[3], buffer.data[4], 0];
            tmp.partial_divide_64(divisor);
            buffer.data[2] = tmp.data[0];
            buffer.data[3] = tmp.data[1];
            buffer.data[4] = tmp.data[2];
        }

        tmp.data = [buffer.data[1], buffer.data[2], buffer.data[3], 0];
        tmp.partial_divide_64(divisor);
        buffer.data[1] = tmp.data[0];
        buffer.data[2] = tmp.data[1];
        buffer.data[3] = tmp.data[2];

        tmp.data = [buffer.data[0], buffer.data[1], buffer.data[2], 0];
        tmp.partial_divide_64(divisor);
        buffer.data[0] = tmp.data[0];
        buffer.data[1] = tmp.data[1];
        buffer.data[2] = tmp.data[2];

        let low64 = buffer.low64() >> shift;
        CalculationResult::Ok(Decimal::from_parts(
            low64 as u32,
            (low64 >> 32as u32,
            0,
            d1.negative,
            d1.scale,
        ))
    } else {
        let divisor_low64 = divisor;
        let divisor = Buf12 {
            data: [
                divisor_low64 as u32,
                (divisor_low64 >> 32as u32,
                (((d2.mid() as u64) + ((d2.hi() as u64) << 32)) >> (32 - shift)) as u32,
            ],
        };

        // Do some division
        if upper == 6 {
            upper -= 1;
            tmp.data = [buffer.data[3], buffer.data[4], buffer.data[5], overflow];
            tmp.partial_divide_96(&divisor);
            buffer.data[3] = tmp.data[0];
            buffer.data[4] = tmp.data[1];
            buffer.data[5] = tmp.data[2];
        }
        if upper == 5 {
            upper -= 1;
            tmp.data = [buffer.data[2], buffer.data[3], buffer.data[4], buffer.data[5]];
            tmp.partial_divide_96(&divisor);
            buffer.data[2] = tmp.data[0];
            buffer.data[3] = tmp.data[1];
            buffer.data[4] = tmp.data[2];
            buffer.data[5] = tmp.data[3];
        }
        if upper == 4 {
            tmp.data = [buffer.data[1], buffer.data[2], buffer.data[3], buffer.data[4]];
            tmp.partial_divide_96(&divisor);
            buffer.data[1] = tmp.data[0];
            buffer.data[2] = tmp.data[1];
            buffer.data[3] = tmp.data[2];
            buffer.data[4] = tmp.data[3];
        }

        tmp.data = [buffer.data[0], buffer.data[1], buffer.data[2], buffer.data[3]];
        tmp.partial_divide_96(&divisor);
        buffer.data[0] = tmp.data[0];
        buffer.data[1] = tmp.data[1];
        buffer.data[2] = tmp.data[2];
        buffer.data[3] = tmp.data[3];

        let low64 = (buffer.low64() >> shift) + ((buffer.data[2as u64) << (32 - shift) << 32);
        CalculationResult::Ok(Decimal::from_parts(
            low64 as u32,
            (low64 >> 32as u32,
            buffer.data[2] >> shift,
            d1.negative,
            d1.scale,
        ))
    }
}

Messung V0.5 in Prozent
C=68 H=86 G=77

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-06-20) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik