<commit_before>﻿namespace Tensor

open System
open System.Numerics


/// A rational number, i.e. a fraction of arbitrary precision.
[<Struct; CustomEquality; CustomComparison; StructuredFormatDisplay("{Pretty}")>]
type Rat =
    
    // The default constructor for structs in .NET initializes all fields to zero and
    // this behavior cannot be changed. Thus we store the denominator minus one
    // to have "0/1" as our default value instead of "0/0" which would be NaN.

    // Rules for encoding non-finite numbers:
    // Num > 0 and Dnm = 0 => +Inf
    // Num < 0 and Dnm = 0 => -Inf
    // Num = 0 and Dnm = 0 => NaN

    /// the numerator
    val Num: bigint 
    /// the denominator minus one
    val private DnmMinusOne: bigint

    /// the denominator
    member a.Dnm = a.DnmMinusOne + bigint.One

    /// Constructs a fraction from numerator and denominator.
    new (num, dnm) = 
        if dnm <> bigint.Zero then
            // not infinity or NaN
            let num, dnm =
                if dnm < bigint.Zero then -num, -dnm
                else num, dnm
            let cd = bigint.GreatestCommonDivisor(num, dnm)
            {Num=num/cd; DnmMinusOne=dnm/cd - bigint.One}
        else
            // infinity or NaN
            match num with
            | _ when num > bigint.Zero -> {Num=bigint.One;      DnmMinusOne=bigint.MinusOne}
            | _ when num < bigint.Zero -> {Num=bigint.MinusOne; DnmMinusOne=bigint.MinusOne}
            | _ ->                        {Num=bigint.Zero;     DnmMinusOne=bigint.MinusOne}

    /// Constructs a fraction from numerator and denominator.
    new (num: int32, dnm: int32) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: uint32, dnm: uint32) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: int64, dnm: int64) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: uint64, dnm: uint64) = Rat (bigint num, bigint dnm)

    /// Constructs an integer rational number.
    new (value) = Rat (value, bigint.One)    

    /// Constructs an integer rational number.
    new (value: int32) = Rat (bigint value)   
    
    /// Constructs an integer rational number.
    new (value: uint32) = Rat (bigint value)    

    /// Constructs an integer rational number.
    new (value: int64) = Rat (bigint value)   
    
    /// Constructs an integer rational number.
    new (value: uint64) = Rat (bigint value)    

    /// True if this is an integer, i.e. denominator is one.
    member a.IsInt = a.Dnm = bigint.One

    /// True is this is positive infinity.
    member a.IsPosInf = 
        a.Num > bigint.Zero && a.Dnm = bigint.Zero

    /// True is this is negative infinity.
    member a.IsNegInf = 
        a.Num < bigint.Zero && a.Dnm = bigint.Zero

    /// True is this is infinity.
    member a.IsInf =
        a.IsPosInf || a.IsNegInf

    /// True if this is not-a-number.
    member a.IsNaN =
        a.Num = bigint.Zero && a.Dnm = bigint.Zero

    /// True if this is a finite number (not infinity and not NaN).
    member a.IsFinite =
        a.Dnm <> bigint.Zero

    /// Fails if this is not an integer rational.
    member private a.CheckInt() =
        if not a.IsInt then
            failwithf "the rational %A is not an integer" a

    // unary and binary operators
    static member (~+) (a: Rat) = a
    static member (~-) (a: Rat) = Rat (-a.Num, a.Dnm)
    static member Abs (a: Rat) = Rat (abs a.Num, a.Dnm)
    static member (+) (a: Rat, b: Rat) = 
        if a.IsNaN || b.IsNaN then Rat.NaN
        else
            match a.IsNegInf, a.IsPosInf, b.IsNegInf, b.IsPosInf with
            |           true,          _,          _,       true -> Rat.NaN
            |              _,       true,       true,          _ -> Rat.NaN
            |           true,          _,          _,          _ -> Rat.NegInf
            |              _,          _,       true,          _ -> Rat.NegInf
            |              _,       true,          _,          _ -> Rat.PosInf
            |              _,          _,          _,       true -> Rat.PosInf
            |          false,      false,      false,      false ->
                Rat (a.Num * b.Dnm + b.Num * a.Dnm, a.Dnm * b.Dnm)
    static member (-) (a: Rat, b: Rat) = a + (-b)
    static member (*) (a: Rat, b: Rat) = 
        Rat (a.Num * b.Num, a.Dnm * b.Dnm)
    static member (/) (a: Rat, b: Rat) = 
        Rat (a.Num * b.Dnm, a.Dnm * b.Num)
    static member (%) (a: Rat, b: Rat) = 
        Rat ((a.Num * b.Dnm) % (b.Num * a.Dnm), a.Dnm * b.Dnm)
    static member get_Sign (a: Rat) = sign a.Num
    static member Zero = Rat (bigint.Zero)
    static member One = Rat (bigint.One)
    static member MinusOne = Rat (bigint.MinusOne)
    static member PosInf = Rat (bigint.One, bigint.Zero)<commit_msg>Rat: Floor, Ceiling<commit_after>﻿namespace Tensor

open System
open System.Numerics


/// A rational number, i.e. a fraction of arbitrary precision.
[<Struct; CustomEquality; CustomComparison; StructuredFormatDisplay("{Pretty}")>]
type Rat =
    
    // The default constructor for structs in .NET initializes all fields to zero and
    // this behavior cannot be changed. Thus we store the denominator minus one
    // to have "0/1" as our default value instead of "0/0" which would be NaN.

    // Rules for encoding non-finite numbers:
    // Num > 0 and Dnm = 0 => +Inf
    // Num < 0 and Dnm = 0 => -Inf
    // Num = 0 and Dnm = 0 => NaN

    /// the numerator
    val Num: bigint 
    /// the denominator minus one
    val private DnmMinusOne: bigint

    /// the denominator
    member a.Dnm = a.DnmMinusOne + bigint.One

    /// Constructs a fraction from numerator and denominator.
    new (num, dnm) = 
        if dnm <> bigint.Zero then
            // not infinity or NaN
            let num, dnm =
                if dnm < bigint.Zero then -num, -dnm
                else num, dnm
            let cd = bigint.GreatestCommonDivisor(num, dnm)
            {Num=num/cd; DnmMinusOne=dnm/cd - bigint.One}
        else
            // infinity or NaN
            match num with
            | _ when num > bigint.Zero -> {Num=bigint.One;      DnmMinusOne=bigint.MinusOne}
            | _ when num < bigint.Zero -> {Num=bigint.MinusOne; DnmMinusOne=bigint.MinusOne}
            | _ ->                        {Num=bigint.Zero;     DnmMinusOne=bigint.MinusOne}

    /// Constructs a fraction from numerator and denominator.
    new (num: int32, dnm: int32) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: uint32, dnm: uint32) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: int64, dnm: int64) = Rat (bigint num, bigint dnm)

    /// Constructs a fraction from numerator and denominator.
    new (num: uint64, dnm: uint64) = Rat (bigint num, bigint dnm)

    /// Constructs an integer rational number.
    new (value) = Rat (value, bigint.One)    

    /// Constructs an integer rational number.
    new (value: int32) = Rat (bigint value)   
    
    /// Constructs an integer rational number.
    new (value: uint32) = Rat (bigint value)    

    /// Constructs an integer rational number.
    new (value: int64) = Rat (bigint value)   
    
    /// Constructs an integer rational number.
    new (value: uint64) = Rat (bigint value)    

    /// True if this is an integer, i.e. denominator is one.
    member a.IsInt = a.Dnm = bigint.One

    /// True is this is positive infinity.
    member a.IsPosInf = 
        a.Num > bigint.Zero && a.Dnm = bigint.Zero

    /// True is this is negative infinity.
    member a.IsNegInf = 
        a.Num < bigint.Zero && a.Dnm = bigint.Zero

    /// True is this is infinity.
    member a.IsInf =
        a.IsPosInf || a.IsNegInf

    /// True if this is not-a-number.
    member a.IsNaN =
        a.Num = bigint.Zero && a.Dnm = bigint.Zero

    /// True if this is a finite number (not infinity and not NaN).
    member a.IsFinite =
        a.Dnm <> bigint.Zero

    /// Fails if this is not an integer rational.
    member private a.CheckInt() =
        if not a.IsInt then
            failwithf "the rational %A is not an integer" a

    // unary and binary operators
    static member (~+) (a: Rat) = a
    static member (~-) (a: Rat) = Rat (-a.Num, a.Dnm)
    static member Abs (a: Rat) = Rat (abs a.Num, a.Dnm)
    static member Floor (a: Rat) = Rat(a.Num - (a.Num % a.Dnm), a.Dnm)
    static member Ceiling (a: Rat) = 
        let r = a.Num % a.Dnm
        if r <> bigint.Zero then Rat(a.Num + (a.Dnm - r), a.Dnm)
        else a
    static member (+) (a: Rat, b: Rat) = 
        if a.IsNaN || b.IsNaN then Rat.NaN
        else
            match a.IsNegInf, a.IsPosInf, b.IsNegInf, b.IsPosInf with
            |           true,          _,          _,       true -> Rat.NaN
            |              _,       true,       true,          _ -> Rat.NaN
            |           true,          _,          _,          _ -> Rat.NegInf
            |              _,          _,       true,          _ -> Rat.NegInf
            |              _,       true,          _,          _ -> Rat.PosInf
            |              _,          _,          _,       true -> Rat.PosInf
            |          false,      false,      false,      false ->
                Rat (a.Num * b.Dnm + b.Num * a.Dnm, a.Dnm * b.Dnm)
    static member (-) (a: Rat, b: Rat) = a + (-b)
    static member (*) (a: Rat, b: Rat) = 
        Rat (a.Num * b.Num, a.Dnm * b.Dnm)
    static member (/) (a: Rat, b: Rat) = 
        Rat (a.Num * b.Dnm, a.Dnm * b.Num)
    static member (%) (a: Rat, b: Rat) = 
        Rat ((a.Num * b.Dnm) % (b.Num * a.Dnm), a.Dnm * b.Dnm)
    static member get_Sign (a: Rat) = sign a.Num
    static member Zero = Rat (bigint.Zero)
    static member One = Rat (bigint.One)
    static member MinusOne = Rat (bigint.MinusOne)
    static member PosInf = Rat (bigint.One, bigint.Zero)
{'fraction_non_alphanumeric': 0.11492879195299273, 'fraction_numerical': 0.006772233841250872, 'mean_word_length': 1.674300932090546, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5355946', 'n_tokens_mistral': 3325, 'n_tokens_neox': 3162, 'n_words': 1065}