Skip to content

Commit 69dd821

Browse files
authored
Merge pull request #310 from gHashTag/feat/multi-language-bindings
feat: add multi-language bindings for GoldenFloat
2 parents f8e6814 + c83e781 commit 69dd821

13 files changed

Lines changed: 1474 additions & 0 deletions

File tree

bindings/javascript/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "golden-float-js"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "WebAssembly bindings for GoldenFloat via wasm-bindgen"
6+
license = "MIT"
7+
8+
[lib]
9+
crate-type = ["cdylib", "rlib"]
10+
11+
[dependencies]
12+
wasm-bindgen = "0.2"
13+
serde = { version = "1", features = ["derive"] }
14+
serde-wasm-bindgen = "0.4"
15+
16+
[profile.release]
17+
opt-level = "z"
18+
lto = true
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* GoldenFloat: Phi-structured floating-point formats for ML and scientific computing
3+
*
4+
* GoldenFloat formats are phi-optimal floating-point representations that
5+
* provide better precision for constants like φ (golden ratio) compared to
6+
* standard IEEE 754 formats.
7+
*/
8+
9+
/**
10+
* GF16: 16-bit phi-structured floating-point format
11+
*/
12+
export class GF16 {
13+
private value: number;
14+
15+
constructor(value: number);
16+
toFloat(): number;
17+
bits(): number;
18+
isZero(): boolean;
19+
isInf(): boolean;
20+
isNan(): boolean;
21+
}
22+
23+
/**
24+
* GF32: 32-bit phi-structured floating-point format
25+
*/
26+
export class GF32 {
27+
private value: number;
28+
29+
constructor(value: number);
30+
toFloat(): number;
31+
bits(): number;
32+
isZero(): boolean;
33+
isInf(): boolean;
34+
isNan(): boolean;
35+
}
36+
37+
/**
38+
* Get the constant phi (golden ratio) as GF16
39+
*/
40+
export function phiGF16(): number;
41+
42+
/**
43+
* Get the constant phi (golden ratio) as GF32
44+
*/
45+
export function phiGF32(): number;
46+
47+
/**
48+
* Check if a value represents positive zero
49+
*/
50+
export function isPositiveZero(value: number): boolean;
51+
52+
/**
53+
* Check if a value represents negative zero
54+
*/
55+
export function isNegativeZero(value: number): boolean;

bindings/javascript/package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "golden-float",
3+
"version": "0.1.0",
4+
"description": "Phi-structured floating-point formats for machine learning and scientific computing",
5+
"main": "golden-float.js",
6+
"types": "golden-float.d.ts",
7+
"module": "es6",
8+
"sideEffects": false,
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/trinity-s3ai/t27"
12+
},
13+
"keywords": [
14+
"golden-float",
15+
"phi",
16+
"floating-point",
17+
"machine-learning",
18+
"webassembly",
19+
"wasm"
20+
],
21+
"author": "Trinity S3AI",
22+
"license": "MIT",
23+
"scripts": {
24+
"build": "wasm-pack build --target bundler",
25+
"test": "node test.js"
26+
},
27+
"devDependencies": {
28+
"wasm-pack": "^0.12.0"
29+
}
30+
}

bindings/javascript/src/lib.rs

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/* phi^2 + phi^-2 = 3 | TRINITY */
2+
3+
use wasm_bindgen::prelude::*;
4+
5+
// ============================================================================
6+
// Helper Functions (implementing GF logic directly)
7+
// ============================================================================
8+
9+
fn gf16_encode(value: f64) -> u16 {
10+
if value == 0.0 {
11+
return if value.is_sign_negative() { 0x8000u16 } else { 0u16 };
12+
}
13+
14+
let sign = if value < 0.0 { 0x8000u16 } else { 0u16 };
15+
let abs_value = if value < 0.0 { -value } else { value };
16+
17+
// Get IEEE 754 binary representation
18+
let bits = abs_value.to_bits();
19+
let ieee_exp = ((bits >> 52) & 0x7FF) as i32 - 1023;
20+
let ieee_mant = bits & 0x000FFFFFFFFFFFFF;
21+
22+
let mut gf16_exp = ieee_exp + 31; // GF16_BIAS = 31
23+
if gf16_exp < 0 { gf16_exp = 0; }
24+
if gf16_exp > 62 { gf16_exp = 62; }
25+
26+
// Convert from 52-bit IEEE mantissa to 9-bit GF16 mantissa
27+
let mut gf16_mant = (ieee_mant >> 43) as u16;
28+
29+
// Round to nearest
30+
let discarded = ieee_mant & 0x7FFFFFFFFFF;
31+
if discarded & 0x4000000000 != 0 {
32+
gf16_mant += 1;
33+
if gf16_mant > 511 {
34+
gf16_mant = 0;
35+
if gf16_exp < 62 { gf16_exp += 1; }
36+
}
37+
}
38+
39+
sign | ((gf16_exp as u16) << 9) | gf16_mant
40+
}
41+
42+
fn gf16_decode(value: u16) -> f64 {
43+
if value == 0x0000 || value == 0x8000 {
44+
return if value == 0x8000 { -0.0f64 } else { 0.0f64 };
45+
}
46+
47+
let sign_f = if (value & 0x8000) != 0 { -1.0f64 } else { 1.0f64 };
48+
let exp = ((value >> 9) & 0x3F) as i32;
49+
let mant = (value & 0x01FF) as f64;
50+
51+
if exp == 63 {
52+
// Special values
53+
return if mant == 0.0 {
54+
if sign_f < 0.0 { f64::NEG_INFINITY } else { f64::INFINITY }
55+
} else {
56+
f64::NAN
57+
};
58+
}
59+
60+
let mant_norm = 1.0f64 + mant / 512.0f64;
61+
let exp_adj = exp - 31;
62+
sign_f * mant_norm * 2.0_f64.powi(exp_adj)
63+
}
64+
65+
fn gf16_is_zero(value: u16) -> bool {
66+
value == 0x0000 || value == 0x8000
67+
}
68+
69+
fn gf16_is_inf(value: u16) -> bool {
70+
let exp = ((value >> 9) & 0x3F) as i32;
71+
let mant = (value & 0x01FF) as i32;
72+
exp == 63 && mant == 0
73+
}
74+
75+
fn gf16_is_nan(value: u16) -> bool {
76+
let exp = ((value >> 9) & 0x3F) as i32;
77+
let mant = (value & 0x01FF) as i32;
78+
exp == 63 && mant != 0
79+
}
80+
81+
fn gf32_encode(value: f64) -> u32 {
82+
if value == 0.0 {
83+
return if value.is_sign_negative() { 0x80000000u32 } else { 0u32 };
84+
}
85+
86+
let sign = if value < 0.0 { 0x80000000u32 } else { 0u32 };
87+
let abs_value = if value < 0.0 { -value } else { value };
88+
89+
let bits = abs_value.to_bits();
90+
let ieee_exp = ((bits >> 52) & 0x7FF) as i32 - 1023;
91+
let ieee_mant = bits & 0x000FFFFFFFFFFFFF;
92+
93+
let mut gf32_exp = ieee_exp + 2047; // GF32_BIAS = 2047
94+
if gf32_exp < 0 { gf32_exp = 0; }
95+
if gf32_exp > 4094 { gf32_exp = 4094; }
96+
97+
// Convert from 52-bit IEEE mantissa to 19-bit GF32 mantissa
98+
let gf32_mant = (ieee_mant >> 33) & 0x7FFFF;
99+
100+
(((sign as u64) | ((gf32_exp as u64) << 19) | (gf32_mant as u64)) & 0xFFFFFFFF) as u32
101+
}
102+
103+
fn gf32_decode(value: u32) -> f64 {
104+
if value == 0 {
105+
return 0.0f64;
106+
}
107+
108+
let sign_f = if (value & 0x80000000) != 0 { -1.0f64 } else { 1.0f64 };
109+
let exp = ((value >> 19) & 0xFFF) as i32;
110+
let mant = (value & 0x7FFFF) as f64;
111+
112+
if exp == 4095 {
113+
return if mant == 0.0 {
114+
if sign_f < 0.0 { f64::NEG_INFINITY } else { f64::INFINITY }
115+
} else {
116+
f64::NAN
117+
};
118+
}
119+
120+
let mant_norm = 1.0f64 + mant / 524288.0f64;
121+
let exp_adj = exp - 2047;
122+
sign_f * mant_norm * 2.0_f64.powi(exp_adj)
123+
}
124+
125+
fn gf32_is_zero(value: u32) -> bool {
126+
value == 0
127+
}
128+
129+
fn gf32_is_inf(value: u32) -> bool {
130+
let exp = ((value >> 19) & 0xFFF) as i32;
131+
exp == 4095
132+
}
133+
134+
fn gf32_is_nan(value: u32) -> bool {
135+
let exp = ((value >> 19) & 0xFFF) as i32;
136+
let mant = (value & 0x7FFFF) as i32;
137+
exp == 4095 && mant != 0
138+
}
139+
140+
// ============================================================================
141+
// JavaScript/Wasm Classes
142+
// ============================================================================
143+
144+
/// GF16: 16-bit phi-structured floating-point format
145+
#[wasm_bindgen]
146+
pub struct GF16 {
147+
value: u16,
148+
}
149+
150+
#[wasm_bindgen]
151+
impl GF16 {
152+
#[wasm_bindgen(constructor)]
153+
pub fn new(value: f64) -> GF16 {
154+
GF16 { value: gf16_encode(value) }
155+
}
156+
157+
pub fn to_float(&self) -> f64 {
158+
gf16_decode(self.value)
159+
}
160+
161+
pub fn bits(&self) -> u16 {
162+
self.value
163+
}
164+
165+
pub fn is_zero(&self) -> bool {
166+
gf16_is_zero(self.value)
167+
}
168+
169+
pub fn is_inf(&self) -> bool {
170+
gf16_is_inf(self.value)
171+
}
172+
173+
pub fn is_nan(&self) -> bool {
174+
gf16_is_nan(self.value)
175+
}
176+
}
177+
178+
/// GF32: 32-bit phi-structured floating-point format
179+
#[wasm_bindgen]
180+
pub struct GF32 {
181+
value: u32,
182+
}
183+
184+
#[wasm_bindgen]
185+
impl GF32 {
186+
#[wasm_bindgen(constructor)]
187+
pub fn new(value: f64) -> GF32 {
188+
GF32 { value: gf32_encode(value) }
189+
}
190+
191+
pub fn to_float(&self) -> f64 {
192+
gf32_decode(self.value)
193+
}
194+
195+
pub fn bits(&self) -> u32 {
196+
self.value
197+
}
198+
199+
pub fn is_zero(&self) -> bool {
200+
gf32_is_zero(self.value)
201+
}
202+
203+
pub fn is_inf(&self) -> bool {
204+
gf32_is_inf(self.value)
205+
}
206+
207+
pub fn is_nan(&self) -> bool {
208+
gf32_is_nan(self.value)
209+
}
210+
}
211+
212+
// ============================================================================
213+
// Utility Functions
214+
// ============================================================================
215+
216+
/// Get the constant phi (golden ratio) as GF16
217+
#[wasm_bindgen]
218+
pub fn phi_gf16() -> u16 {
219+
gf16_encode(1.618033988749895)
220+
}
221+
222+
/// Get the constant phi (golden ratio) as GF32
223+
#[wasm_bindgen]
224+
pub fn phi_gf32() -> u32 {
225+
gf32_encode(1.618033988749895)
226+
}
227+
228+
/// Check if the value represents positive zero
229+
#[wasm_bindgen]
230+
pub fn is_positive_zero(value: u16) -> bool {
231+
value == 0x0000
232+
}
233+
234+
/// Check if the value represents negative zero
235+
#[wasm_bindgen]
236+
pub fn is_negative_zero(value: u16) -> bool {
237+
value == 0x8000
238+
}

bindings/python/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "golden-float-py"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "Python bindings for GoldenFloat via PyO3"
6+
license = "MIT"
7+
8+
[lib]
9+
name = "golden_float"
10+
crate-type = ["cdylib"]
11+
12+
[dependencies]
13+
pyo3 = { version = "0.22", features = ["extension-module", "abi3"] }
14+
15+
[build-dependencies]
16+
golden-float-ffi = { path = "../../ffi" }

0 commit comments

Comments
 (0)