Skip to content

Commit

Permalink
implemented Real::log() and Real::logf(), though log() isn't exported…
Browse files Browse the repository at this point in the history
… due to poor performance (will be revisited in the future)
  • Loading branch information
christianschmitz committed Sep 14, 2024
1 parent 98033f8 commit 61e7e30
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@helios-lang/compiler",
"version": "0.17.0-81",
"version": "0.17.0-82",
"description": "Helios is a Domain Specific Language that compiles to Plutus-Core (i.e. Cardano on-chain validator scripts). Helios is a non-Haskell alternative to Plutus. With this library you can compile Helios scripts and build Cardano transactions, all you need to build 100% client-side dApps for Cardano.",
"main": "src/index.js",
"types": "types/index.d.ts",
Expand Down
141 changes: 141 additions & 0 deletions src/codegen/makeRawFuncs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2766,6 +2766,147 @@ export function makeRawFunctions(simplify, isTestnet) {
)
add(new RawFunc("__helios__real__min", "__helios__int__min"))
add(new RawFunc("__helios__real__max", "__helios__int__max"))
add(
new RawFunc(
"__helios__real__log",
`(self) -> {
__core__ifThenElse(
__core__lessThanEqualsInteger(self, 0),
() -> {
__helios__error("log domain error")
},
() -> {
precision = __core__multiplyInteger(__helios__real__ONE, 10000);
x = __core__multiplyInteger(self, 10000);
taylor = (x) -> {
x_minus_1 = __core__subtractInteger(x, precision);
even = (sum, term, i) -> {
d = __core__divideInteger(term, i);
s = __core__subtractInteger(sum, d);
__core__ifThenElse(
__core__equalsInteger(i, 20),
() -> {
s
},
() -> {
t = __core__divideInteger(__core__multiplyInteger(term, x_minus_1), precision);
odd(s, t, __core__addInteger(i, 1))
}
)()
};
odd = (sum, term, i) -> {
d = __core__divideInteger(term, i);
s = __core__addInteger(sum, d);
t = __core__divideInteger(__core__multiplyInteger(term, x_minus_1), precision);
__core__trace(
__helios__real__show(t)()
, even(s, t, __core__addInteger(i, 1)))
};
__core__trace(
__helios__real__show(x_minus_1)(),
odd(0, x_minus_1, 1)
)
};
reduce = (x, n) -> {
__core__ifThenElse(
__core__lessThanInteger(x, __core__multiplyInteger(precision, 2)),
() -> {
__core__trace(
__helios__int__show(n)(),
() -> {
sqrtx = __helios__int__sqrt(
__helios__int____mul(x, precision));
lna = __core__multiplyInteger(2, taylor(sqrtx));
lnx = __core__addInteger(
lna,
__core__multiplyInteger(n, 6931471806)
);
__helios__real__round_calc_result(__core__divideInteger__safe(lnx, 1000))
}
)()
},
() -> {
reduce(__core__divideInteger(x, 2), __core__addInteger(n, 1))
}
)()
};
reduce(x, 0)
}
)()
}`
)
)
add(
new RawFunc(
"__helios__real__logf",
`(self) -> {
__core__ifThenElse(
__core__lessThanEqualsInteger(self, 0),
() -> {
__helios__error("logf domain error")
},
() -> {
approx_1_to_165 = (x) -> {
__core__divideInteger__safe(
__core__subtractInteger(
__core__multiplyInteger(x, x),
__core__multiplyInteger(__helios__real__ONE, __helios__real__ONE)
),
__core__multiplyInteger(2, x)
)
};
approx_1_to_2 = (x) -> {
__core__ifThenElse(
__core__lessThanInteger(x, 1_350_000 /*1_648_721*/),
() -> {
approx_1_to_165(x)
},
() -> {
__helios__real____add(
500_000,
approx_1_to_165(
__helios__real__divf(
x,
1_648_721
)
)
)
}
)()
};
reduce = (x, n) -> {
__core__ifThenElse(
__core__lessThanInteger(x, __helios__real__ONE),
() -> {
reduce(__core__multiplyInteger(x, 2), __core__subtractInteger(n, 1))
},
() -> {
__core__ifThenElse(
__core__lessThanInteger(x, __core__multiplyInteger(__helios__real__ONE, 2)),
() -> {
__core__addInteger(
approx_1_to_2(x),
__core__multiplyInteger(n, 693147)
)
},
() -> {
reduce(__core__divideInteger__safe(x, 2), __core__addInteger(n, 1))
}
)()
}
)()
};
reduce(self, 0)
}
)()
}`
)
)

// Bool builtins
addSerializeFunc("__helios__bool")
Expand Down
2 changes: 1 addition & 1 deletion src/program/version.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = "0.17.0-81"
export const VERSION = "0.17.0-82"
2 changes: 2 additions & 0 deletions src/typecheck/primitives.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ export const RealType = new GenericType({
__sub: new FuncType([self, self], self),
__sub1: new FuncType([self, IntType], self),
divf: new FuncType([self, self], self),
// log: new FuncType([self], self), // TODO: make this accurate to 6 decimal places at a reasonable cost
logf: new FuncType([self], self),
max: new FuncType([self, self], self),
min: new FuncType([self, self], self),
mulf: new FuncType([self, self], self),
Expand Down
74 changes: 74 additions & 0 deletions test/Real.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,80 @@ describe("Real", () => {
})
})

describe("Real::logf", () => {
const runner = compileForRun(`testing real_logf
func main(a: Real) -> Real {
Real::logf(a)
}`)

it("logf(0) throws an error", () => {
runner([real(0)], { error: "" })
})

it("logf(1) == 0", () => {
runner([real(1)], real(0))
})

it("logf(0.01) == -4.602654 (2 decimal places of precision compared to -4.605170)", () => {
runner([real(0.01)], real(-4.602654))
})

it("logf(0.1) == -2.302589 (5 decimal places of precision compared to -2.302585)", () => {
runner([real(0.1)], real(-2.302589))
})

it("logf(2) == 0.693147", () => {
runner([real(2)], real(0.693147))
})

it("logf(2.718281) == 0.998795 (3 decimal places of precision compared to 1.0)", () => {
runner([real(2.718282)], real(0.998795))
})

it("logf(1.95) == 0.668617 (3 decimal places of precision compared to 0.667829)", () => {
runner([real(1.95)], real(0.668617))
})

it("logf(10) == 2.304441 (2 decimal places of precision compared to 2.302585)", () => {
runner([real(10)], real(2.304441))
})

it("logf(100) == 4.605143 (4 decimal places of precision compared to 4.605170)", () => {
runner([real(100)], real(4.605143))
})
})

/*describe("Real::log", () => {
const runner = compileForRun(`testing real_log
func main(a: Real) -> Real {
Real::log(a)
}`, {dumpCostPrefix: "Real::log"})
it("log(0) throws an error", () => {
runner([real(0)], {error: ""})
})
it("log(0.1) == -2.302585", () => {
runner([real(0.1)], real(-2.302585))
})
it("log(1) == 0", () => {
runner([real(1)], real(0))
})
it("log(2) == 0.693147", () => {
runner([real(2)], real(0.693147))
})
it("log(2.718281) == 1.0", () => {
runner([real(2.718282)], real(1.0))
})
it("log(1.95) == 1.0", () => {
runner([real(1.95)], real(0.667829))
})
})*/

describe("Real::sqrt", () => {
const runner = compileForRun(`testing real_sqrt
func main(a: Real) -> Real {
Expand Down
2 changes: 1 addition & 1 deletion test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export function compileForRun(mainSrc, options = {}) {

if (options.dumpCostPrefix) {
console.log(
`Cost of ${options.dumpCostPrefix}: mem=${costMem1}, cpu=${costCpu1}`
`Cost of ${options.dumpCostPrefix}: mem=${costMem1}, cpu=${costCpu1}, lovelace=${Number(costMem1) * 0.0577 + Number(costCpu1) * 0.0000721}`
)
}
}
Expand Down

0 comments on commit 61e7e30

Please sign in to comment.