├── .gitignore ├── Makefile ├── README.md ├── fp64.c ├── sinlut.h └── test.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.dll 3 | *.so -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install : 2 | gcc -g -Wall -fPIC --shared -o fp64.dll fp64.c ../lua-5.3.5/src/lua53.dll -I../lua-5.3.5/src -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LuaFixedPoint64 2 | A fixed point 64bits library for Lua. 3 | 4 | 5 | In 64 bit architecture, you can use lightuserdata type for fp64, build it with marco `USELIGHTUSERDATA` or add `#define USELIGHTUSERDATA` to fp64.c. 6 | -------------------------------------------------------------------------------- /fp64.c: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "lua.h" 11 | #include "lauxlib.h" 12 | #include "sinlut.h" 13 | 14 | 15 | typedef int64_t fp64_t; 16 | static const fp64_t fp64_one = 0x0000000100000000; 17 | static const fp64_t fp64_pi = 0x3243F6A88; 18 | static const fp64_t fp64_e = 0x2B7E15163; 19 | static const fp64_t fp64_piover2 = 0x1921FB544; 20 | static const fp64_t fp64_pitimes2 = 0x6487ED511; 21 | static const fp64_t fp64_rad2deg = 0x394BB834D1; 22 | static const fp64_t fp64_deg2rad = 0x477D1A8; 23 | static const fp64_t fp64_epsilon = 0x100; 24 | static const fp64_t fp64_zero = 0; 25 | static const fp64_t fp64_piover4 = 0xC90FDAA2; 26 | static const fp64_t fp64_3piover4 = 0x25b2f8fe6; 27 | static const fp64_t fp64_max = 0x7FFFFFFFFFFFFFFF; 28 | static const fp64_t fp64_min = 0x8000000000000000; 29 | 30 | 31 | #ifdef USELIGHTUSERDATA 32 | #if INTPTR_MAX != INT64_MAX 33 | #undef USELIGHTUSERDATA 34 | #endif 35 | #endif 36 | 37 | static fp64_t fpmul(fp64_t a, fp64_t b) 38 | { 39 | int64_t A = a >> 32, C = b >> 32; 40 | uint64_t B = a & 0xFFFFFFFF, D = b & 0xFFFFFFFF; 41 | int64_t AC = A * C; 42 | int64_t AD_CB = A * D + C * B; 43 | uint64_t BD = B * D; 44 | 45 | int64_t product_hi = AC + (AD_CB >> 32); 46 | 47 | uint64_t ad_cb_temp = AD_CB << 32; 48 | uint64_t product_lo = BD + ad_cb_temp; 49 | 50 | if (product_lo < BD) 51 | product_hi++; 52 | 53 | uint64_t product_lo_tmp = product_lo; 54 | product_lo -= 0x80000000; 55 | product_lo -= (uint64_t)product_hi >> 63; 56 | if (product_lo > product_lo_tmp) 57 | product_hi--; 58 | fp64_t result = (product_hi << 32) | (product_lo >> 32); 59 | result += 1; 60 | return result; 61 | } 62 | 63 | #ifdef __GNUC__ 64 | #define clz(x) (__builtin_clzll(x) - (8 * sizeof(long long) - 64)) 65 | #else 66 | static uint8_t clz(uint64_t x) 67 | { 68 | uint8_t result = 0; 69 | if (x == 0) return 32; 70 | while (!(x & 0xF000000000000000)) { result += 4; x <<= 4; } 71 | while (!(x & 0x8000000000000000)) { result += 1; x <<= 1; } 72 | return result; 73 | } 74 | #endif 75 | 76 | static fp64_t fpdiv(fp64_t a, fp64_t b) 77 | { 78 | if (b == 0) return 0; 79 | uint64_t remainder = (a >= 0) ? a : -a; 80 | uint64_t divider = (b >= 0) ? b : -b; 81 | uint64_t quotient = 0; 82 | int bit_pos = 33; 83 | 84 | while (!(divider & 0xF) && bit_pos >= 4) 85 | { 86 | divider >>= 4; 87 | bit_pos -= 4; 88 | } 89 | 90 | while (remainder && bit_pos >= 0) 91 | { 92 | int shift = clz(remainder); 93 | if (shift > bit_pos) shift = bit_pos; 94 | remainder <<= shift; 95 | bit_pos -= shift; 96 | 97 | uint64_t div = remainder / divider; 98 | remainder = remainder % divider; 99 | quotient += div << bit_pos; 100 | 101 | remainder <<= 1; 102 | bit_pos--; 103 | } 104 | quotient++; 105 | fp64_t result = quotient >> 1; 106 | if ((a ^ b) & 0x8000000000000000) 107 | { 108 | result = -result; 109 | } 110 | return result; 111 | } 112 | 113 | static fp64_t fpsqrt(fp64_t value) 114 | { 115 | uint8_t neg = (value < 0); 116 | uint64_t num = (neg ? -value : value); 117 | uint64_t result = 0; 118 | uint64_t bit; 119 | uint8_t n; 120 | 121 | //most values <= 65535 122 | if (num & 0xFFFF000000000000) 123 | bit = (uint64_t)1 << 62; 124 | else 125 | bit = (uint64_t)1 << 46; 126 | while (bit > num) bit >>= 2; 127 | 128 | for (n = 0; n < 2; n++) 129 | { 130 | while (bit) 131 | { 132 | if (num >= result + bit) 133 | { 134 | num -= result + bit; 135 | result = (result >> 1) + bit; 136 | } 137 | else 138 | { 139 | result = result >> 1; 140 | } 141 | bit >>= 2; 142 | } 143 | 144 | if (n == 0) 145 | { 146 | //frac last 16bits 147 | if (num > 0xFFFFFFFF) 148 | { 149 | num -= result; 150 | num = (num << 32) - 0x80000000; 151 | result = (result << 32) + 0x80000000; 152 | } 153 | else 154 | { 155 | num <<= 32; 156 | result <<= 32; 157 | } 158 | bit = 1 << 30; 159 | } 160 | } 161 | 162 | //rounding 163 | if (num > result) 164 | { 165 | result++; 166 | } 167 | 168 | return (neg ? -(fp64_t)result : (fp64_t)result); 169 | } 170 | 171 | static fp64_t fpsin(fp64_t value) 172 | { 173 | fp64_t temp = value % (fp64_pitimes2); 174 | if (temp < 0) temp += fp64_pitimes2; 175 | bool sign = true; 176 | if (temp >= fp64_pi) { 177 | temp -= fp64_pi; 178 | sign = false; 179 | } 180 | if (temp >= fp64_piover2) 181 | temp = fp64_pi - temp; 182 | 183 | uint32_t index = temp >> 15; 184 | 185 | fp64_t result = fp64_one; 186 | if (index <= sin_lut_count) { 187 | fp64_t frac = (temp & 0x7FFF) << 17; 188 | fp64_t a = sin_lut[index]; 189 | fp64_t b = index == sin_lut_count ? fp64_one : sin_lut[index + 1]; 190 | result = fpmul(a, fp64_one - frac) + fpmul(b, frac); 191 | } 192 | return sign ? result : -result; 193 | } 194 | 195 | static fp64_t fpcos(fp64_t value) 196 | { 197 | return fpsin(value + fp64_piover2); 198 | } 199 | 200 | static fp64_t fptan(fp64_t value) 201 | { 202 | return fpdiv(fpsin(value), fpcos(value)); 203 | } 204 | 205 | static fp64_t fpatan2(fp64_t y, fp64_t x) 206 | { 207 | fp64_t abs_inY, mask, angle, r, r_3; 208 | mask = (y >> (sizeof(fp64_t) * 8 - 1)); 209 | abs_inY = (y + mask) ^ mask; 210 | 211 | if (x >= 0) { 212 | r = fpdiv(x - abs_inY, x + abs_inY); 213 | r_3 = fpmul(fpmul(r, r), r); 214 | angle = fpmul(0x32400000, r_3) - fpmul(0xFB500000, r) + fp64_piover4; 215 | } 216 | else { 217 | r = fpdiv(x + abs_inY, abs_inY - x); 218 | r_3 = fpmul(fpmul(r, r), r); 219 | angle = fpmul(0x32400000, r_3) - fpmul(0xFB500000, r) + fp64_3piover4; 220 | } 221 | return y > 0 ? angle : -angle; 222 | } 223 | 224 | static fp64_t fpatan(fp64_t v) 225 | { 226 | return fpatan2(v, fp64_one); 227 | } 228 | 229 | static fp64_t fpasin(fp64_t x) 230 | { 231 | if (x > fp64_one || x < -fp64_one) 232 | { 233 | return fp64_zero; 234 | } 235 | fp64_t out; 236 | out = (fp64_one - fpmul(x, x)); 237 | out = fpdiv(x, fpsqrt(out)); 238 | out = fpatan(out); 239 | return out; 240 | } 241 | 242 | static fp64_t fpacos(fp64_t x) 243 | { 244 | return (fp64_piover2 - fpasin(x)); 245 | } 246 | 247 | static inline fp64_t from_number(lua_Number l) 248 | { 249 | lua_Number temp = l * fp64_one; 250 | temp += (temp >= 0) ? 0.5f : -0.5f; 251 | return (fp64_t)(temp); 252 | } 253 | static inline fp64_t from_integer(lua_Integer d) 254 | { 255 | return d * fp64_one; 256 | } 257 | 258 | static fp64_t fpexp(fp64_t x) 259 | { 260 | if (x == 0) return fp64_one; 261 | if (x == fp64_one) return fp64_e; 262 | if (x >= 92288378626) return fp64_max; 263 | if (x <= -95265423098) return fp64_zero; 264 | 265 | bool neg = x < 0; 266 | if (neg) x = -x; 267 | 268 | fp64_t result = x + fp64_one; 269 | fp64_t term = x; 270 | 271 | for (int i = 2; i < 30; i++) 272 | { 273 | term = fpmul(term, fpdiv(x, from_integer(i))); 274 | result += term; 275 | 276 | if ((term < 500000) && ((i > 15) || (term < 20000))) 277 | break; 278 | } 279 | if (neg) result = fpdiv(fp64_one, result); 280 | return result; 281 | } 282 | 283 | static fp64_t fplog(fp64_t x) 284 | { 285 | fp64_t guess = from_integer(2); 286 | fp64_t delta; 287 | int scaling = 0; 288 | int count = 0; 289 | 290 | if (x <= 0) 291 | return fp64_min; 292 | 293 | // Bring the value to the most accurate range (1 < x < 100) 294 | const fp64_t e_to_fourth = 234497268814; 295 | while (x > from_integer(2)) 296 | { 297 | x = fpdiv(x, e_to_fourth); 298 | scaling += 4; 299 | } 300 | 301 | while (x < fp64_one) 302 | { 303 | x = fpmul(x, e_to_fourth); 304 | scaling -= 4; 305 | } 306 | 307 | do 308 | { 309 | // Solving e(x) = y using Newton's method 310 | // f(x) = e(x) - y 311 | // f'(x) = e(x) 312 | fp64_t e = fpexp(guess); 313 | delta = fpdiv(x - e, e); 314 | 315 | // It's unlikely that logarithm is very large, so avoid overshooting. 316 | if (delta > from_integer(3)) 317 | delta = from_integer(3); 318 | 319 | guess += delta; 320 | } while ((count++ < 10) 321 | && ((delta > 1) || (delta < -1))); 322 | 323 | return guess + from_integer(scaling); 324 | } 325 | 326 | static inline fp64_t fprs(fp64_t x) 327 | { 328 | fp64_t y = (x >> 1) + (x & 1); 329 | return y; 330 | } 331 | 332 | static fp64_t fplog2_inner(fp64_t x) 333 | { 334 | fp64_t result = 0; 335 | 336 | while (x >= from_integer(2)) 337 | { 338 | result++; 339 | x = fprs(x); 340 | } 341 | 342 | if (x == 0) return (result << 32); 343 | 344 | uint_fast8_t i; 345 | for (i = 32; i > 0; i--) 346 | { 347 | x = fpmul(x, x); 348 | result <<= 1; 349 | if (x >= from_integer(2)) 350 | { 351 | result |= 1; 352 | x = fprs(x); 353 | } 354 | } 355 | x = fpmul(x, x); 356 | if (x >= from_integer(2)) result++; 357 | 358 | return result; 359 | } 360 | 361 | fp64_t fplog2(fp64_t x) 362 | { 363 | if (x <= 0) return fp64_min; 364 | 365 | // If the input is less than one, the result is -log2(1.0 / in) 366 | if (x < fp64_one) 367 | { 368 | fp64_t inverse = fpdiv(fp64_one, x); 369 | return -fplog2_inner(inverse); 370 | } 371 | 372 | // If input >= 1, just proceed as normal. 373 | // Note that x == fix16_one is a special case, where the answer is 0. 374 | return fplog2_inner(x); 375 | } 376 | 377 | static fp64_t from_str(const char* buf) 378 | { 379 | while (isspace(*buf)) 380 | buf++; 381 | bool negative = (*buf == '-'); 382 | if (*buf == '+' || *buf == '-') 383 | buf++; 384 | 385 | uint64_t intpart = 0; 386 | int count = 0; 387 | while (isdigit(*buf)) 388 | { 389 | intpart *= 10; 390 | intpart += *buf++ - '0'; 391 | count++; 392 | } 393 | fp64_t value = intpart << 32; 394 | 395 | if (*buf == '.' || *buf == ',') 396 | { 397 | buf++; 398 | 399 | int64_t fracpart = 0; 400 | int64_t scale = 1; 401 | while (isdigit(*buf) && scale < 10000000000) 402 | { 403 | scale *= 10; 404 | fracpart *= 10; 405 | fracpart += *buf++ - '0'; 406 | } 407 | 408 | value = value + fpdiv(fracpart, scale); 409 | } 410 | return negative ? -value : value; 411 | } 412 | 413 | static char* itoa_loop(char* buf, uint64_t scale, uint64_t value, bool skip) 414 | { 415 | while (scale) 416 | { 417 | unsigned digit = (value / scale); 418 | if (!skip || digit || scale == 1) 419 | { 420 | skip = false; 421 | *buf++ = '0' + digit; 422 | value %= scale; 423 | } 424 | scale /= 10; 425 | } 426 | return buf; 427 | } 428 | 429 | static void to_str(fp64_t value, char* buf) 430 | { 431 | uint64_t uvalue = (value > 0) ? value : -value; 432 | if (value < 0) 433 | *buf++ = '-'; 434 | uint64_t intpart = uvalue >> 32; 435 | uint64_t fracpart = uvalue & 0xFFFFFFFF; 436 | uint64_t scale = 1000000000; 437 | fracpart = fpmul(fracpart, scale); 438 | if (fracpart >= scale) 439 | { 440 | intpart++; 441 | fracpart -= scale; 442 | } 443 | buf = itoa_loop(buf, 1000000000, intpart, true); 444 | if (fracpart != 0) 445 | { 446 | *buf++ = '.'; 447 | buf = itoa_loop(buf, scale / 10, fracpart, false); 448 | buf--; 449 | while(*buf == '0') buf--; 450 | buf++; 451 | } 452 | *buf = '\0'; 453 | } 454 | 455 | static inline fp64_t fpceil(fp64_t n) { return (n & 0xFFFFFFFF00000000) + (n & 0x00000000FFFFFFFF ? fp64_one : 0); } 456 | static inline fp64_t fpfloor(fp64_t n) { return (n & 0xFFFFFFFF00000000); } 457 | static inline fp64_t fpabs(fp64_t x) { return (x < 0 ? -x : x); } 458 | static inline fp64_t fpmax(fp64_t x, fp64_t y) { return x > y ? x : y; } 459 | static inline fp64_t fpmin(fp64_t x, fp64_t y) { return x < y ? x : y; } 460 | static inline fp64_t fpclamp(fp64_t x, fp64_t y, fp64_t z) { return fpmin(fpmax(x, y), z);} 461 | 462 | static inline lua_Number to_number(fp64_t n) { return (lua_Number)n / fp64_one; } 463 | 464 | static bool _isfp64(lua_State* L, int pos) 465 | { 466 | if (lua_getmetatable(L, pos)) 467 | { 468 | luaL_getmetatable(L, "fp64"); 469 | int equal = lua_rawequal(L, -1, -2); 470 | lua_pop(L, 2); 471 | return equal; 472 | } 473 | return false; 474 | } 475 | 476 | LUALIB_API void pushfp64(lua_State* L, fp64_t n) 477 | { 478 | #ifdef USELIGHTUSERDATA 479 | lua_pushlightuserdata(L, (void*)n); 480 | #else 481 | fp64_t* p = (fp64_t*)lua_newuserdata(L, sizeof(fp64_t)); 482 | *p = n; 483 | luaL_getmetatable(L, "fp64"); 484 | lua_setmetatable(L, -2); 485 | #endif 486 | } 487 | 488 | static inline fp64_t _parse_str(lua_State* L, int pos) 489 | { 490 | const char* str = lua_tostring(L, pos); 491 | return from_str(str); 492 | } 493 | 494 | static int64_t tofp64(lua_State* L, int pos) 495 | { 496 | fp64_t n = 0; 497 | int type = lua_type(L, pos); 498 | 499 | switch(type) 500 | { 501 | case LUA_TNUMBER: 502 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503 503 | if (lua_tonumber(L, pos) == lua_tointeger(L, pos)) 504 | #else 505 | if (lua_isinteger(L, pos)) 506 | #endif 507 | { 508 | lua_Integer l = lua_tointeger(L, pos); 509 | if (l == 0) 510 | { 511 | n = fp64_zero; 512 | } 513 | else 514 | { 515 | n = from_integer(lua_tointeger(L, pos)); 516 | } 517 | } 518 | else 519 | { 520 | n = from_number(lua_tonumber(L, pos)); 521 | } 522 | break; 523 | case LUA_TSTRING: 524 | n = _parse_str(L, pos); 525 | break; 526 | #ifdef USELIGHTUSERDATA 527 | case LUA_TLIGHTUSERDATA: 528 | n = (int64_t)lua_touserdata(L, pos); 529 | #else 530 | case LUA_TUSERDATA: 531 | if (_isfp64(L, pos)) 532 | { 533 | n = *(fp64_t*)lua_touserdata(L, pos); 534 | } 535 | #endif 536 | break; 537 | default: 538 | n = fp64_zero; 539 | const char *msg = lua_pushfstring(L, "%s expected, got %s", "fp64", luaL_typename(L, pos)); 540 | return luaL_argerror(L, pos, msg); 541 | break; 542 | } 543 | return n; 544 | } 545 | 546 | static int _fp64add(lua_State* L) 547 | { 548 | fp64_t lhs = tofp64(L, 1); 549 | fp64_t rhs = tofp64(L, 2); 550 | pushfp64(L, lhs + rhs); 551 | return 1; 552 | } 553 | 554 | static int _fp64sub(lua_State* L) 555 | { 556 | fp64_t lhs = tofp64(L, 1); 557 | fp64_t rhs = tofp64(L, 2); 558 | pushfp64(L, lhs - rhs); 559 | return 1; 560 | } 561 | 562 | static int _fp64mul(lua_State* L) 563 | { 564 | fp64_t lhs = tofp64(L, 1); 565 | fp64_t rhs = tofp64(L, 2); 566 | pushfp64(L, fpmul(lhs, rhs)); 567 | return 1; 568 | } 569 | 570 | static int _fp64div(lua_State* L) 571 | { 572 | fp64_t lhs = tofp64(L, 1); 573 | fp64_t rhs = tofp64(L, 2); 574 | 575 | if (rhs == 0) 576 | { 577 | return luaL_error(L, "div by zero"); 578 | } 579 | 580 | pushfp64(L, fpdiv(lhs , rhs)); 581 | return 1; 582 | } 583 | 584 | static int _fp64mod(lua_State* L) 585 | { 586 | fp64_t lhs = tofp64(L, 1); 587 | fp64_t rhs = tofp64(L, 2); 588 | if (rhs == 0) 589 | { 590 | return luaL_error(L, "mod by zero"); 591 | } 592 | pushfp64(L, lhs % rhs); 593 | return 1; 594 | } 595 | 596 | static int _fp64unm(lua_State* L) 597 | { 598 | fp64_t lhs = *(fp64_t*)lua_touserdata(L, 1); 599 | pushfp64(L, -lhs); 600 | return 1; 601 | } 602 | 603 | static int _fp64max(lua_State * L) 604 | { 605 | fp64_t lhs = tofp64(L, 1); 606 | fp64_t rhs = tofp64(L, 2); 607 | pushfp64(L, fpmax(lhs, rhs)); 608 | return 1; 609 | } 610 | 611 | static int _fp64min(lua_State * L) 612 | { 613 | fp64_t lhs = tofp64(L, 1); 614 | fp64_t rhs = tofp64(L, 2); 615 | pushfp64(L, fpmin(lhs, rhs)); 616 | return 1; 617 | } 618 | 619 | static int _fp64clamp(lua_State * L) 620 | { 621 | fp64_t x = tofp64(L, 1); 622 | fp64_t lo = tofp64(L, 2); 623 | fp64_t hi = tofp64(L, 3); 624 | pushfp64(L, fpclamp(x, lo, hi)); 625 | return 1; 626 | } 627 | 628 | static int _fp64eq(lua_State* L) 629 | { 630 | fp64_t lhs = *(fp64_t*)lua_touserdata(L, 1); 631 | fp64_t rhs = *(fp64_t*)lua_touserdata(L, 2); 632 | lua_pushboolean(L, lhs == rhs); 633 | return 1; 634 | } 635 | 636 | static int _fp64lt(lua_State* L) 637 | { 638 | fp64_t lhs = tofp64(L, 1); 639 | fp64_t rhs = tofp64(L, 2); 640 | lua_pushboolean(L, lhs < rhs); 641 | return 1; 642 | } 643 | 644 | static int _fp64le(lua_State* L) 645 | { 646 | fp64_t lhs = tofp64(L, 1); 647 | fp64_t rhs = tofp64(L, 2); 648 | lua_pushboolean(L, lhs <= rhs); 649 | return 1; 650 | } 651 | 652 | static int _fp64tostring(lua_State* L) 653 | { 654 | fp64_t n = tofp64(L, 1); 655 | char temp[32]; 656 | to_str(n, temp); 657 | lua_pushstring(L, temp); 658 | return 1; 659 | } 660 | 661 | static int _fp64tohex(lua_State* L) 662 | { 663 | fp64_t n = tofp64(L, 1); 664 | char temp[32]; 665 | sprintf(temp, "%llx", n); 666 | lua_pushstring(L, temp); 667 | return 1; 668 | } 669 | 670 | 671 | static int _fp64equals(lua_State* L) 672 | { 673 | int64_t lhs = tofp64(L, 1); 674 | int64_t rhs = tofp64(L, 2); 675 | lua_pushboolean(L, lhs == rhs); 676 | return 1; 677 | } 678 | 679 | static int _fp64compare(lua_State *L) 680 | { 681 | int64_t lhs = tofp64(L, 1); 682 | int64_t rhs = tofp64(L, 2); 683 | int res = lhs == rhs ? 0 : (lhs < rhs ? -1 : 1); 684 | lua_pushinteger(L, res); 685 | return 1; 686 | } 687 | 688 | static int _fp64tonumber(lua_State *L) 689 | { 690 | fp64_t n = tofp64(L, 1); 691 | lua_Number l = to_number(n); 692 | lua_pushnumber(L, l); 693 | return 1; 694 | } 695 | 696 | static int _fp64sqrt(lua_State* L) 697 | { 698 | fp64_t n = tofp64(L, 1); 699 | fp64_t l = fpsqrt(n); 700 | pushfp64(L, l); 701 | return 1; 702 | } 703 | 704 | static int _fp64ceil(lua_State* L) 705 | { 706 | fp64_t n = tofp64(L, 1); 707 | fp64_t l = fpceil(n); 708 | pushfp64(L, l); 709 | return 1; 710 | } 711 | 712 | static int _fp64floor(lua_State* L) 713 | { 714 | fp64_t n = tofp64(L, 1); 715 | fp64_t l = fpfloor(n); 716 | pushfp64(L, l); 717 | return 1; 718 | } 719 | 720 | static int _fp64abs(lua_State* L) 721 | { 722 | fp64_t n = tofp64(L, 1); 723 | fp64_t l = fpabs(n); 724 | pushfp64(L, l); 725 | return 1; 726 | } 727 | 728 | 729 | static int _fp64sin(lua_State* L) 730 | { 731 | fp64_t angle = tofp64(L, 1); 732 | pushfp64(L, fpsin(angle)); 733 | return 1; 734 | } 735 | 736 | static int _fp64cos(lua_State* L) 737 | { 738 | fp64_t angle = tofp64(L, 1); 739 | pushfp64(L, fpcos(angle)); 740 | return 1; 741 | } 742 | 743 | static int _fp64tan(lua_State* L) 744 | { 745 | fp64_t angle = tofp64(L, 1); 746 | pushfp64(L, fptan(angle)); 747 | return 1; 748 | } 749 | 750 | static int _fp64asin(lua_State* L) 751 | { 752 | fp64_t value = tofp64(L, 1); 753 | pushfp64(L, fpasin(value)); 754 | return 1; 755 | } 756 | static int _fp64acos(lua_State* L) 757 | { 758 | fp64_t value = tofp64(L, 1); 759 | pushfp64(L, fpacos(value)); 760 | return 1; 761 | } 762 | 763 | static int _fp64atan(lua_State* L) 764 | { 765 | fp64_t value = tofp64(L, 1); 766 | pushfp64(L, fpatan(value)); 767 | return 1; 768 | } 769 | 770 | static int _fp64atan2(lua_State* L) 771 | { 772 | fp64_t lhs = tofp64(L, 1); 773 | fp64_t rhs = tofp64(L, 2); 774 | pushfp64(L, fpatan2(lhs, rhs)); 775 | return 1; 776 | } 777 | 778 | static int _fp64exp(lua_State* L) 779 | { 780 | fp64_t x = tofp64(L, 1); 781 | pushfp64(L, fpexp(x)); 782 | return 1; 783 | } 784 | 785 | static int _fp64log(lua_State* L) 786 | { 787 | fp64_t x = tofp64(L, 1); 788 | pushfp64(L, fplog(x)); 789 | return 1; 790 | } 791 | 792 | static int _fp64log2(lua_State* L) 793 | { 794 | fp64_t x = tofp64(L, 1); 795 | pushfp64(L, fplog2(x)); 796 | return 1; 797 | } 798 | 799 | 800 | static int newfp64(lua_State* L) 801 | { 802 | int64_t n = fp64_zero; 803 | int type = lua_type(L, 1); 804 | 805 | if (type == LUA_TSTRING) 806 | { 807 | n = _parse_str(L, 1); 808 | } 809 | else if (type == LUA_TNUMBER) 810 | { 811 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503 812 | if(lua_tonumber(L, 1) == lua_tointeger(L, 1)) 813 | #else 814 | if(lua_isinteger(L, 1)) 815 | #endif 816 | { 817 | n = from_integer(lua_tointeger(L, 1)); 818 | } 819 | else 820 | { 821 | n = from_number(lua_tonumber(L, 1)); 822 | } 823 | } 824 | pushfp64(L, n); 825 | return 1; 826 | } 827 | 828 | static const struct luaL_Reg lib_fp64_meta [] = { 829 | {"__add", _fp64add}, 830 | {"__sub", _fp64sub}, 831 | {"__mul", _fp64mul}, 832 | {"__div", _fp64div}, 833 | {"__mod", _fp64mod}, 834 | {"__unm", _fp64unm}, 835 | {"__eq", _fp64eq}, 836 | {"__lt", _fp64lt}, 837 | {"__le", _fp64le}, 838 | {"__tostring", _fp64tostring}, 839 | {"__index", NULL}, 840 | {NULL, NULL} 841 | }; 842 | 843 | static const struct luaL_Reg lib_fp64 [] = { 844 | {"hex", _fp64tohex}, 845 | {"tostring", _fp64tostring}, 846 | {"tonumber", _fp64tonumber}, 847 | {"compare", _fp64compare}, 848 | {"min", _fp64min}, 849 | {"max", _fp64max}, 850 | {"clamp", _fp64clamp}, 851 | {"equals", _fp64equals}, 852 | {"sqrt", _fp64sqrt}, 853 | {"ceil", _fp64ceil}, 854 | {"floor", _fp64floor}, 855 | {"abs", _fp64abs}, 856 | {"sin", _fp64sin}, 857 | {"cos", _fp64cos}, 858 | {"tan", _fp64tan}, 859 | {"asin", _fp64asin}, 860 | {"acos", _fp64acos}, 861 | {"atan", _fp64atan}, 862 | {"atan2", _fp64atan2}, 863 | {"exp", _fp64exp}, 864 | {"log", _fp64log}, 865 | {"log2", _fp64log2}, 866 | {"new", newfp64}, 867 | {"one", NULL}, 868 | {"pi", NULL}, 869 | {"epsilon", NULL}, 870 | {"rad2deg", NULL}, 871 | {"deg2rad", NULL}, 872 | {"e", NULL}, 873 | {NULL, NULL} 874 | }; 875 | 876 | #if !defined(LUAJIT_VERSION) && LUA_VERSION_NUM < 502 877 | /* Compatibility for Lua 5.1 & Luajit. 878 | * 879 | * luaL_setfuncs() is used to create a module table where the functions have 880 | * Code borrowed from Lua 5.2 source. 881 | * 882 | * For Lua 5.1 without JIT, 883 | * use this luaL_setfuncs function from 5.2. 884 | * For Lua 5.1 with JIT(Luajit), 885 | * since Luajit already defines luaL_setfuncs, there is no need to redefine it here to avoid multiple definitions. */ 886 | static void luaL_setfuncs(lua_State *l, const luaL_Reg *reg, int nup) 887 | { 888 | int i; 889 | 890 | luaL_checkstack(l, nup, "too many upvalues"); 891 | for (; reg->name != NULL; reg++) 892 | { 893 | for (i = 0; i < nup; i++) 894 | lua_pushvalue(l, -nup); 895 | lua_pushcclosure(l, reg->func, nup); 896 | lua_setfield(l, -(nup + 2), reg->name); 897 | } 898 | lua_pop(l, nup); 899 | } 900 | #endif 901 | 902 | #if !defined(LUAJIT_VERSION) && LUA_VERSION_NUM < 502 903 | /* Compatibility for Lua 5.1 & Luajit. 904 | * 905 | * For Lua 5.1 without JIT, use this luaL_newlib defined here. 906 | * For Lua 5.1 with JIT(Luajit), since Luajit already defines luaL_newlib, there is no need to redefine it here to avoid multiple definitions. */ 907 | #define luaL_newlib(L, l) (lua_newtable(L), luaL_register(L, NULL, l)) 908 | #endif 909 | 910 | int luaopen_fp64(lua_State* L) 911 | { 912 | luaL_newmetatable(L, "fp64"); 913 | luaL_setfuncs(L, lib_fp64_meta, 0); 914 | luaL_newlib(L, lib_fp64); 915 | pushfp64(L, fp64_pi); 916 | lua_setfield(L, -2, "pi"); 917 | pushfp64(L, fp64_one); 918 | #ifdef USELIGHTUSERDATA 919 | //set metatable for light userdata 920 | lua_pushvalue(L, -3); 921 | lua_setmetatable(L, -2); 922 | #endif 923 | lua_setfield(L, -2, "one"); 924 | pushfp64(L, fp64_epsilon); 925 | lua_setfield(L, -2, "epsilon"); 926 | pushfp64(L, fp64_rad2deg); 927 | lua_setfield(L, -2, "rad2deg"); 928 | pushfp64(L, fp64_deg2rad); 929 | lua_setfield(L, -2, "deg2rad"); 930 | pushfp64(L, fp64_e); 931 | lua_setfield(L, -2, "e"); 932 | lua_pushvalue(L, -1); 933 | lua_setfield(L, -3, "__index"); 934 | return 1; 935 | } 936 | 937 | #ifdef __cplusplus 938 | } 939 | #endif -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | fp64 = require("fp64") 2 | 3 | local f = fp64.new(5.259451158) 4 | f= f / 5 5 | f = -f 6 | f = f * 3 7 | f= f:sin() 8 | print(f + fp64.pi) 9 | print(fp64.tan(6)) 10 | print(f:tonumber()) 11 | print(f:hex()) 12 | local s = fp64.sqrt(fp64.e) 13 | print(s:log()) 14 | print(fp64.log2(2 ^ 10)) --------------------------------------------------------------------------------