Skip to content

Commit 597e24c

Browse files
committed
add a table-based implementation of cosine
this is a space-optimized implementation of cosine. it's about 12k smaller than core lib's "proper" cosine. Gives about 9 bits amplitude resolution, and divides the waveform into 1024 time positions. Good enough for generating tones on a crappy speaker. Later on if anyone needs to "really" do cosine or sine, we'll have a footgun for them, but...let's hope Rust fixes issue rust-lang/rust#105734 before then, and we can deprecate this library in favor of the mathematically accurate and canonical cosine implementation.
1 parent ee14188 commit 597e24c

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

libs/cos_table/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "cos_table"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["bunnie <[email protected]>"]
6+
description = "Space-optimized cosine table lookup"
7+
8+
[dependencies]

libs/cos_table/src/lib.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
COS_TABLE generated with:
3+
4+
#! /usr/bin/env python3
5+
import math
6+
print("const COS_TABLE: [u8; 256] = [", end="")
7+
for i in range(256):
8+
if i % 16 == 0:
9+
print("\n", end="")
10+
print("{:03}, ".format(int(255.0 * math.cos( ((3.14159265359 / 2.0) / 256) * float(i) ))), end="")
11+
print("];")
12+
*/
13+
/// One quarter of a cosine wave. The other four quarters are generated through symmetry.
14+
const COS_TABLE: [u8; 256] = [
15+
255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253,
16+
253, 253, 253, 253, 253, 252, 252, 252, 252, 252, 251, 251, 251, 250, 250, 250,
17+
250, 249, 249, 249, 248, 248, 248, 247, 247, 246, 246, 246, 245, 245, 244, 244,
18+
244, 243, 243, 242, 242, 241, 241, 240, 240, 239, 239, 238, 237, 237, 236, 236,
19+
235, 234, 234, 233, 233, 232, 231, 231, 230, 229, 229, 228, 227, 227, 226, 225,
20+
224, 224, 223, 222, 221, 221, 220, 219, 218, 217, 217, 216, 215, 214, 213, 212,
21+
212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 201, 200, 199, 198,
22+
197, 196, 195, 194, 193, 192, 191, 189, 188, 187, 186, 185, 184, 183, 182, 181,
23+
180, 179, 178, 176, 175, 174, 173, 172, 171, 170, 168, 167, 166, 165, 164, 162,
24+
161, 160, 159, 158, 156, 155, 154, 153, 151, 150, 149, 148, 146, 145, 144, 142,
25+
141, 140, 139, 137, 136, 135, 133, 132, 131, 129, 128, 127, 125, 124, 122, 121,
26+
120, 118, 117, 116, 114, 113, 111, 110, 109, 107, 106, 104, 103, 101, 100, 099,
27+
097, 096, 094, 093, 091, 090, 088, 087, 085, 084, 082, 081, 079, 078, 077, 075,
28+
074, 072, 071, 069, 068, 066, 064, 063, 061, 060, 058, 057, 055, 054, 052, 051,
29+
049, 048, 046, 045, 043, 042, 040, 038, 037, 035, 034, 032, 031, 029, 028, 026,
30+
024, 023, 021, 020, 018, 017, 015, 014, 012, 010, 009, 007, 006, 004, 003, 001,
31+
];
32+
33+
use std::f32::consts::PI;
34+
enum Quadrant {
35+
FirstNormNorm,
36+
SecondReverseInvert,
37+
ThirdNormInvert,
38+
FourthReverseNorm,
39+
}
40+
/// LUT-based cosine computation. Has an `8-bit` resolution. Used to coarsely compute
41+
/// a cosine without relying on `std` functions. The concerns driving this implementation are:
42+
///
43+
/// - code size
44+
/// - xous-core issue #285 and https://github.com/rust-lang/rust/issues/105734
45+
///
46+
/// The issue above means any attempt to use `cos` (or any transcendental function) from
47+
/// Rust math library leads to a link time error. Until Rust can fix this regression we have
48+
/// to implement our own cosine function, or use `thin` LTO which adds about 7% to the size
49+
/// of the kernel, making it by far the single largest contributing factor to kernel bloat.
50+
51+
pub fn cos(a: f32) -> f32 {
52+
let pos = a % (2.0 * PI);
53+
let q = if pos < (PI / 2.0) {
54+
Quadrant::FirstNormNorm
55+
} else if pos < (PI) {
56+
Quadrant::SecondReverseInvert
57+
} else if pos < (3.0 * PI / 2.0) {
58+
Quadrant::ThirdNormInvert
59+
} else {
60+
Quadrant::FourthReverseNorm
61+
};
62+
let idx = (256.0 * (a % (PI / 2.0)) / (PI / 2.0)) as usize;
63+
match q {
64+
Quadrant::FirstNormNorm => {
65+
(COS_TABLE[idx] as f32) / 255.0
66+
},
67+
Quadrant::SecondReverseInvert => {
68+
(COS_TABLE[255-idx] as f32) / -255.0
69+
},
70+
Quadrant::ThirdNormInvert => {
71+
(COS_TABLE[idx] as f32) / -255.0
72+
},
73+
Quadrant::FourthReverseNorm => {
74+
(COS_TABLE[255-idx] as f32) / 255.0
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)