Getting started in C¶
Kt-Math's Kotlin/Native build is also a C library: every GitHub release ships it, prebuilt, for the desktop platforms. No Kotlin or Gradle is needed to use it.
Download¶
Pick the zip of your platform among the assets of the latest release:
| Platform | Asset | Library | Header |
|---|---|---|---|
| Linux x64 | kt-math-VERSION-linuxX64.zip |
libktmath.so |
libktmath_api.h |
| Linux ARM64 | kt-math-VERSION-linuxArm64.zip |
libktmath.so |
libktmath_api.h |
| macOS (Apple Silicon) | kt-math-VERSION-macosArm64.zip |
libktmath.dylib |
libktmath_api.h |
| Windows x64 | kt-math-VERSION-mingwX64.zip |
ktmath.dll (plus ktmath.def) |
ktmath_api.h |
Each library is self-contained: the Kotlin runtime is linked into it. On Windows, every libktmath_ prefix below is
ktmath_ instead (ktmath_symbols(), ktmath_kref_...), as in the header's name: include ktmath_api.h.
curl -LO https://github.com/gciatto/kt-math/releases/download/VERSION/kt-math-VERSION-linuxX64.zip
unzip kt-math-VERSION-linuxX64.zip -d ktmath
Write a program¶
The header declares a single function, libktmath_symbols(), returning a structure that mirrors Kotlin's packages and
classes: lib->kotlin.root.org.gciatto.kt.math.BigInteger.times(x, y) is Kotlin's x * y. Kotlin objects are
handles, to release when no longer needed:
// Every Kotlin object is a handle (a struct holding a pointer) to dispose of with DisposeStablePointer, every returned
// string is to dispose of with DisposeString; overloads get trailing underscores, in declaration order. Kotlin
// exceptions abort the process: the parse*OrNull functions return null handles instead.
#include <stdio.h>
#include <string.h>
#include "libktmath_api.h"
static libktmath_ExportedSymbols *lib;
static int failures = 0;
#define KT_MATH (lib->kotlin.root.org.gciatto.kt.math)
#define DISPOSE(handle) lib->DisposeStablePointer((handle).pinned)
// Checks that a string returned by Kotlin is the expected one, then frees it
static void expect(const char *what, const char *actual, const char *expected) {
if (strcmp(actual, expected) != 0) {
printf("FAILED %s: expected %s, got %s\n", what, expected, actual);
failures++;
} else {
printf("ok %s = %s\n", what, actual);
}
lib->DisposeString(actual);
}
static void big_integers(libktmath_kref_org_gciatto_kt_math_BigFactory factory) {
libktmath_kref_org_gciatto_kt_math_BigInteger x =
KT_MATH.BigFactory.parseBigInteger(factory, "123456789012345678901234567890", 10);
libktmath_kref_org_gciatto_kt_math_BigInteger y = KT_MATH.BigFactory.bigIntegerOf(factory, 42);
libktmath_kref_org_gciatto_kt_math_BigInteger product = KT_MATH.BigInteger.times(x, y);
expect("x * 42", KT_MATH.BigInteger.toString_(product), "5185185138518518513851851851380");
libktmath_kref_org_gciatto_kt_math_BigInteger quotient = KT_MATH.BigInteger.div(x, y);
expect("x / 42", KT_MATH.BigInteger.toString_(quotient), "2939447357436801878600823045");
expect("x in hex", KT_MATH.BigInteger.toString(x, 16), "18ee90ff6c373e0ee4e3f0ad2");
if (KT_MATH.BigInteger.compare(x, y) <= 0) {
printf("FAILED compare(x, 42) > 0\n");
failures++;
}
libktmath_kref_org_gciatto_kt_math_BigInteger invalid = KT_MATH.BigFactory.parseBigIntegerOrNull(factory, "12x", 10);
if (invalid.pinned != NULL) {
printf("FAILED parseBigIntegerOrNull(\"12x\") is null\n");
failures++;
}
DISPOSE(quotient);
DISPOSE(product);
DISPOSE(y);
DISPOSE(x);
}
static void big_decimals(libktmath_kref_org_gciatto_kt_math_BigFactory factory) {
libktmath_kref_org_gciatto_kt_math_MathContext_Companion contexts = KT_MATH.MathContext.Companion._instance();
libktmath_kref_org_gciatto_kt_math_MathContext unlimited = KT_MATH.MathContext.Companion.get_UNLIMITED(contexts);
libktmath_kref_org_gciatto_kt_math_BigDecimal a = KT_MATH.BigFactory.parseBigDecimal(factory, "1.10", unlimited);
libktmath_kref_org_gciatto_kt_math_BigDecimal b = KT_MATH.BigFactory.bigDecimalOf(factory, 3, unlimited);
libktmath_kref_org_gciatto_kt_math_RoundingMode half_even = KT_MATH.RoundingMode.HALF_EVEN.get();
libktmath_kref_org_gciatto_kt_math_MathContext ten_digits = KT_MATH.MathContext.MathContext(10, half_even);
libktmath_kref_org_gciatto_kt_math_BigDecimal quotient = KT_MATH.BigDecimal.div_(a, b, ten_digits);
expect("1.10 / 3", KT_MATH.BigDecimal.toPlainString(quotient), "0.3666666667");
libktmath_kref_org_gciatto_kt_math_BigDecimal root = KT_MATH.BigDecimal.sqrt(b, ten_digits);
expect("sqrt(3)", KT_MATH.BigDecimal.toPlainString(root), "1.732050808");
libktmath_kref_org_gciatto_kt_math_BigDecimal log = KT_MATH.big.log(b, ten_digits); // big-math's functions
expect("log(3)", KT_MATH.BigDecimal.toPlainString(log), "1.098612289");
DISPOSE(log);
DISPOSE(root);
DISPOSE(quotient);
DISPOSE(ten_digits);
DISPOSE(half_even);
DISPOSE(b);
DISPOSE(a);
DISPOSE(unlimited);
DISPOSE(contexts);
}
static void big_rationals(libktmath_kref_org_gciatto_kt_math_BigFactory factory) {
libktmath_kref_org_gciatto_kt_math_BigRational third = KT_MATH.BigFactory.parseBigRational(factory, "1/3");
libktmath_kref_org_gciatto_kt_math_BigRational sixth = KT_MATH.BigFactory.bigRationalOf_____(factory, 1, 6);
libktmath_kref_org_gciatto_kt_math_BigRational sum = KT_MATH.BigRational.plus(third, sixth);
libktmath_kref_org_gciatto_kt_math_BigRational reduced = KT_MATH.BigRational.reduce(sum);
expect("1/3 + 1/6", KT_MATH.BigRational.toRationalString(reduced), "1/2");
libktmath_kref_org_gciatto_kt_math_BigRational invalid = KT_MATH.BigFactory.parseBigRationalOrNull(factory, "1/0");
if (invalid.pinned != NULL) {
printf("FAILED parseBigRationalOrNull(\"1/0\") is null\n");
failures++;
}
DISPOSE(reduced);
DISPOSE(sum);
DISPOSE(sixth);
DISPOSE(third);
}
int main(void) {
lib = libktmath_symbols();
libktmath_kref_org_gciatto_kt_math_BigFactory_Companion companion = KT_MATH.BigFactory.Companion._instance();
libktmath_kref_org_gciatto_kt_math_BigFactory factory = KT_MATH.BigFactory.Companion.get_default(companion);
big_integers(factory);
big_decimals(factory);
big_rationals(factory);
return failures == 0 ? 0 : 1;
}
This is the beginning of Kt-Math's own C usage test, compiled and run by CI: src/nativeUsageTest/c/usage.c goes on to
call every other function of the C API, a reference for each of them.
Compile and run¶
cc usage.c -I ktmath -L ktmath -lktmath -Wl,-rpath,"$PWD/ktmath" -o usage
./usage
cc usage.c -I ktmath -L ktmath -lktmath -Wl,-rpath,"$PWD/ktmath" -o usage
./usage
A library downloaded with a browser is quarantined by macOS: xattr -d com.apple.quarantine ktmath/libktmath.dylib.
gcc usage.c -I ktmath -L ktmath -lktmath -o usage.exe
cp ktmath/ktmath.dll .
./usage.exe
With MSVC, create an import library from the definitions file first: lib /def:ktmath.def /out:ktmath.lib /machine:x64.
Going further¶
- Call Kt-Math from C: the conventions of the C API (handles, strings, overloads, exceptions), and how to build the library yourself, e.g. for other Kotlin/Native targets.
- Getting started in Kotlin: the same API from Kotlin/Native code, through Gradle.
- API reference: every class and function, under the same names in C.