Skip to content

Commit

Permalink
refactor: log
Browse files Browse the repository at this point in the history
  • Loading branch information
qazxcdswe123 committed Sep 30, 2024
1 parent 92ed43a commit ae9678e
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 45 deletions.
48 changes: 3 additions & 45 deletions double/log.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn frexp(f : Double) -> (Double, Int) {
return (frac, exp)
}

/// @alert deprecated "Use `@math::ln` instead"
pub fn ln(self : Double) -> Double {
if self.is_nan() || self.is_inf() {
return self
Expand All @@ -83,6 +84,7 @@ pub fn ln(self : Double) -> Double {
k * ln2_hi - (hfsq - (s * (hfsq + r) + k * ln2_lo) - f)
}

/// @alert deprecated "Use `@math::log2` instead"
pub fn log2(self : Double) -> Double {
let (f, e) = frexp(self)
if f == 0.5 {
Expand All @@ -91,51 +93,7 @@ pub fn log2(self : Double) -> Double {
ln(f) / ln2 + e.to_double()
}

/// @alert deprecated "Use `@math.log10` instead"
pub fn log10(self : Double) -> Double {
ln(self) / ln10
}

test "log2 log10" {
// log2
assert_eq!(3.0.log2(), 1.584962500721156)
assert_eq!(2.0.log2(), 1.0)
assert_eq!(1.0.log2(), 0.0)
assert_eq!(0.5.log2(), -1.0)
assert_eq!(0.25.log2(), -2.0)
assert_eq!(0.1.log2(), -3.321928094887362)

// log10
assert_eq!(0.2.log10(), -0.6989700043360187)
assert_eq!(15.0.log10(), 1.1760912590556811)
}

test "ln" {
assert_true!(not_a_number.ln().is_nan())
assert_true!(infinity.ln().is_pos_inf())
assert_true!(neg_infinity.ln().is_neg_inf())
assert_true!((-1.0).ln().is_nan())
assert_true!(0.0.ln().is_neg_inf())
assert_true!((-0.0).ln().is_neg_inf())
assert_eq!(50.0.ln(), 3.912023005428146)
assert_eq!(2.0.ln(), 0.6931471805599453)
assert_eq!(1.1125369292536007e-308.ln(), -709.0895657128241)
assert_eq!(5.562684646268003e-309.ln(), -709.782712893384)
assert_true!(
match frexp(0.0) {
(0.0, 0) => true
_ => false
},
)
assert_true!(
match frexp(infinity) {
(f, 0) => if f.is_pos_inf() { true } else { false }
_ => false
},
)
assert_true!(
match frexp(not_a_number) {
(f, 0) => if f.is_nan() { true } else { false }
_ => false
},
)
}
141 changes: 141 additions & 0 deletions math/log.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ported from https://github.com/golang/go/blob/master/src/math/log.go

let sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974

let ln2 = 0.693147180559945309417232121458176568075500134360255254120680009

let ln10 = 2.30258509299404568401799145468436420760110148862877297603332790

let ln2_hi = 6.93147180369123816490e-01 // 3fe62e42 fee00000

let ln2_lo = 1.90821492927058770002e-10 // 3dea39ef 35793c76

let l1 = 6.666666666666735130e-01 // 3FE55555 55555593

let l2 = 3.999999999940941908e-01 // 3FD99999 9997FA04

let l3 = 2.857142874366239149e-01 // 3FD24924 94229359

let l4 = 2.222219843214978396e-01 // 3FCC71C5 1D8E78AF

let l5 = 1.818357216161805012e-01 // 3FC74664 96CB03DE

let l6 = 1.531383769920937332e-01 // 3FC39A09 D078C69F

let l7 = 1.479819860511658591e-01 // 3FC2F112 DF3E5244

fn normalize(f : Double) -> (Double, Int) {
if f.abs() < @double.min_positive {
return (f * 1L.lsl(52).to_double(), -52)
}
(f, 0)
}

fn frexp(f : Double) -> (Double, Int) {
if f == 0.0 || f.is_inf() || f.is_nan() {
return (f, 0)
}
let (norm_f, exp) = normalize(f)
let u = norm_f.reinterpret_as_i64()
let exp = exp + u.lsr(52).land(0x7FFL).to_int() - 1022
let frac = u
.land(0x7FFL.lsl(52).lnot())
.lor(1022L.lsl(52))
.reinterpret_as_double()
return (frac, exp)
}

pub fn ln(input : Double) -> Double {
if input.is_nan() || input.is_inf() {
return input
} else if input < 0.0 {
return @double.not_a_number
} else if input == 0.0 {
return @double.neg_infinity
}
let (f1, ki) = frexp(input)
let (f, k) = if f1 < sqrt2 / 2.0 {
(f1 * 2.0 - 1.0, (ki - 1).to_double())
} else {
(f1 - 1.0, ki.to_double())
}
let s = f / (2.0 + f)
let s2 = s * s
let s4 = s2 * s2
let t1 = s2 * (l1 + s4 * (l3 + s4 * (l5 + s4 * l7)))
let t2 = s4 * (l2 + s4 * (l4 + s4 * l6))
let r = t1 + t2
let hfsq = 0.5 * f * f
k * ln2_hi - (hfsq - (s * (hfsq + r) + k * ln2_lo) - f)
}

pub fn log2(input : Double) -> Double {
let (f, e) = frexp(input)
if f == 0.5 {
return e.to_double() - 1.0
}
ln(f) / ln2 + e.to_double()
}

pub fn log10(input : Double) -> Double {
ln(input) / ln10
}

test "log2 log10" {
// log2
assert_eq!(log2(3.0), 1.584962500721156)
assert_eq!(log2(2.0), 1.0)
assert_eq!(log2(1.0), 0.0)
assert_eq!(log2(0.5), -1.0)
assert_eq!(log2(0.25), -2.0)
assert_eq!(log2(0.1), -3.321928094887362)

// log10
assert_eq!(log10(0.2), -0.6989700043360187)
assert_eq!(log10(15.0), 1.1760912590556811)
}

test "ln" {
assert_true!(ln(@double.not_a_number).is_nan())
assert_true!(ln(@double.infinity).is_pos_inf())
assert_true!(ln(@double.neg_infinity).is_neg_inf())
assert_true!(ln(-1.0).is_nan())
assert_true!(ln(0.0).is_neg_inf())
assert_true!(ln(-0.0).is_neg_inf())
assert_eq!(ln(50.0), 3.912023005428146)
assert_eq!(ln(2.0), 0.6931471805599453)
assert_eq!(ln(1.1125369292536007e-308), -709.0895657128241)
assert_eq!(ln(5.562684646268003e-309), -709.782712893384)
assert_true!(
match frexp(0.0) {
(0.0, 0) => true
_ => false
},
)
assert_true!(
match frexp(@double.infinity) {
(f, 0) => if f.is_pos_inf() { true } else { false }
_ => false
},
)
assert_true!(
match frexp(@double.not_a_number) {
(f, 0) => if f.is_nan() { true } else { false }
_ => false
},
)
}

0 comments on commit ae9678e

Please sign in to comment.