123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- // stb_divide.h - v0.94 - public domain - Sean Barrett, Feb 2010
- // Three kinds of divide/modulus of signed integers.
- //
- // HISTORY
- //
- // v0.94 Fix integer overflow issues
- // v0.93 2020-02-02 Write useful exit() value from main()
- // v0.92 2019-02-25 Fix warning
- // v0.91 2010-02-27 Fix euclidean division by INT_MIN for non-truncating C
- // Check result with 64-bit math to catch such cases
- // v0.90 2010-02-24 First public release
- //
- // USAGE
- //
- // In *ONE* source file, put:
- //
- // #define STB_DIVIDE_IMPLEMENTATION
- // // #define C_INTEGER_DIVISION_TRUNCATES // see Note 1
- // // #define C_INTEGER_DIVISION_FLOORS // see Note 2
- // #include "stb_divide.h"
- //
- // Other source files should just include stb_divide.h
- //
- // Note 1: On platforms/compilers that you know signed C division
- // truncates, you can #define C_INTEGER_DIVISION_TRUNCATES.
- //
- // Note 2: On platforms/compilers that you know signed C division
- // floors (rounds to negative infinity), you can #define
- // C_INTEGER_DIVISION_FLOORS.
- //
- // You can #define STB_DIVIDE_TEST in which case the implementation
- // will generate a main() and compiling the result will create a
- // program that tests the implementation. Run it with no arguments
- // and any output indicates an error; run it with any argument and
- // it will also print the test results. Define STB_DIVIDE_TEST_64
- // to a 64-bit integer type to avoid overflows in the result-checking
- // which give false negatives.
- //
- // ABOUT
- //
- // This file provides three different consistent divide/mod pairs
- // implemented on top of arbitrary C/C++ division, including correct
- // handling of overflow of intermediate calculations:
- //
- // trunc: a/b truncates to 0, a%b has same sign as a
- // floor: a/b truncates to -inf, a%b has same sign as b
- // eucl: a/b truncates to sign(b)*inf, a%b is non-negative
- //
- // Not necessarily optimal; I tried to keep it generally efficient,
- // but there may be better ways.
- //
- // Briefly, for those who are not familiar with the problem, we note
- // the reason these divides exist and are interesting:
- //
- // 'trunc' is easy to implement in hardware (strip the signs,
- // compute, reapply the signs), thus is commonly defined
- // by many languages (including C99)
- //
- // 'floor' is simple to define and better behaved than trunc;
- // for example it divides integers into fixed-size buckets
- // without an extra-wide bucket at 0, and for a fixed
- // divisor N there are only |N| possible moduli.
- //
- // 'eucl' guarantees fixed-sized buckets *and* a non-negative
- // modulus and defines division to be whatever is needed
- // to achieve that result.
- //
- // See "The Euclidean definition of the functions div and mod"
- // by Raymond Boute (1992), or "Division and Modulus for Computer
- // Scientists" by Daan Leijen (2001)
- //
- // We assume of the built-in C division:
- // (a) modulus is the remainder for the corresponding division
- // (b) a/b truncates if a and b are the same sign
- //
- // Property (a) requires (a/b)*b + (a%b)==a, and is required by C.
- // Property (b) seems to be true of all hardware but is *not* satisfied
- // by the euclidean division operator we define, so it's possibly not
- // always true. If any such platform turns up, we can add more cases.
- // (Possibly only stb_div_trunc currently relies on property (b).)
- //
- // LICENSE
- //
- // See end of file for license information.
- #ifndef INCLUDE_STB_DIVIDE_H
- #define INCLUDE_STB_DIVIDE_H
- #ifdef __cplusplus
- extern "C" {
- #endif
- extern int stb_div_trunc(int value_to_be_divided, int value_to_divide_by);
- extern int stb_div_floor(int value_to_be_divided, int value_to_divide_by);
- extern int stb_div_eucl (int value_to_be_divided, int value_to_divide_by);
- extern int stb_mod_trunc(int value_to_be_divided, int value_to_divide_by);
- extern int stb_mod_floor(int value_to_be_divided, int value_to_divide_by);
- extern int stb_mod_eucl (int value_to_be_divided, int value_to_divide_by);
- #ifdef __cplusplus
- }
- #endif
- #ifdef STB_DIVIDE_IMPLEMENTATION
- #if defined(__STDC_VERSION) && __STDC_VERSION__ >= 19901
- #ifndef C_INTEGER_DIVISION_TRUNCATES
- #define C_INTEGER_DIVISION_TRUNCATES
- #endif
- #endif
- #ifndef INT_MIN
- #include <limits.h> // if you have no limits.h, #define INT_MIN yourself
- #endif
- // the following macros are designed to allow testing
- // other platforms by simulating them
- #ifndef STB_DIVIDE_TEST_FLOOR
- #define stb__div(a,b) ((a)/(b))
- #define stb__mod(a,b) ((a)%(b))
- #else
- // implement floor-style divide on trunc platform
- #ifndef C_INTEGER_DIVISION_TRUNCATES
- #error "floor test requires truncating division"
- #endif
- #undef C_INTEGER_DIVISION_TRUNCATES
- int stb__div(int v1, int v2)
- {
- int q = v1/v2, r = v1%v2;
- if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
- return q-1;
- else
- return q;
- }
- int stb__mod(int v1, int v2)
- {
- int r = v1%v2;
- if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
- return r+v2;
- else
- return r;
- }
- #endif
- int stb_div_trunc(int v1, int v2)
- {
- #ifdef C_INTEGER_DIVISION_TRUNCATES
- return v1/v2;
- #else
- if (v1 >= 0 && v2 <= 0)
- return -stb__div(-v1,v2); // both negative to avoid overflow
- if (v1 <= 0 && v2 >= 0)
- if (v1 != INT_MIN)
- return -stb__div(v1,-v2); // both negative to avoid overflow
- else
- return -stb__div(v1+v2,-v2)-1; // push v1 away from wrap point
- else
- return v1/v2; // same sign, so expect truncation
- #endif
- }
- int stb_div_floor(int v1, int v2)
- {
- #ifdef C_INTEGER_DIVISION_FLOORS
- return v1/v2;
- #else
- if (v1 >= 0 && v2 < 0) {
- if (v2 + 1 >= INT_MIN + v1) // check if increasing v1's magnitude overflows
- return -stb__div((v2+1)-v1,v2); // nope, so just compute it
- else
- return -stb__div(-v1,v2) + ((-v1)%v2 ? -1 : 0);
- }
- if (v1 < 0 && v2 >= 0) {
- if (v1 != INT_MIN) {
- if (v1 + 1 >= INT_MIN + v2) // check if increasing v1's magnitude overflows
- return -stb__div((v1+1)-v2,-v2); // nope, so just compute it
- else
- return -stb__div(-v1,v2) + (stb__mod(v1,-v2) ? -1 : 0);
- } else // it must be possible to compute -(v1+v2) without overflowing
- return -stb__div(-(v1+v2),v2) + (stb__mod(-(v1+v2),v2) ? -2 : -1);
- } else
- return v1/v2; // same sign, so expect truncation
- #endif
- }
- int stb_div_eucl(int v1, int v2)
- {
- int q,r;
- #ifdef C_INTEGER_DIVISION_TRUNCATES
- q = v1/v2;
- r = v1%v2;
- #else
- // handle every quadrant separately, since we can't rely on q and r flor
- if (v1 >= 0)
- if (v2 >= 0)
- return stb__div(v1,v2);
- else if (v2 != INT_MIN)
- q = -stb__div(v1,-v2), r = stb__mod(v1,-v2);
- else
- q = 0, r = v1;
- else if (v1 != INT_MIN)
- if (v2 >= 0)
- q = -stb__div(-v1,v2), r = -stb__mod(-v1,v2);
- else if (v2 != INT_MIN)
- q = stb__div(-v1,-v2), r = -stb__mod(-v1,-v2);
- else // if v2 is INT_MIN, then we can't use -v2, but we can't divide by v2
- q = 1, r = v1-q*v2;
- else // if v1 is INT_MIN, we have to move away from overflow place
- if (v2 >= 0)
- q = -stb__div(-(v1+v2),v2)-1, r = -stb__mod(-(v1+v2),v2);
- else if (v2 != INT_MIN)
- q = stb__div(-(v1-v2),-v2)+1, r = -stb__mod(-(v1-v2),-v2);
- else // for INT_MIN / INT_MIN, we need to be extra-careful to avoid overflow
- q = 1, r = 0;
- #endif
- if (r >= 0)
- return q;
- else
- return q + (v2 > 0 ? -1 : 1);
- }
- int stb_mod_trunc(int v1, int v2)
- {
- #ifdef C_INTEGER_DIVISION_TRUNCATES
- return v1%v2;
- #else
- if (v1 >= 0) { // modulus result should always be positive
- int r = stb__mod(v1,v2);
- if (r >= 0)
- return r;
- else
- return r - (v2 < 0 ? v2 : -v2);
- } else { // modulus result should always be negative
- int r = stb__mod(v1,v2);
- if (r <= 0)
- return r;
- else
- return r + (v2 < 0 ? v2 : -v2);
- }
- #endif
- }
- int stb_mod_floor(int v1, int v2)
- {
- #ifdef C_INTEGER_DIVISION_FLOORS
- return v1%v2;
- #else
- if (v2 >= 0) { // result should always be positive
- int r = stb__mod(v1,v2);
- if (r >= 0)
- return r;
- else
- return r + v2;
- } else { // result should always be negative
- int r = stb__mod(v1,v2);
- if (r <= 0)
- return r;
- else
- return r + v2;
- }
- #endif
- }
- int stb_mod_eucl(int v1, int v2)
- {
- int r = stb__mod(v1,v2);
- if (r >= 0)
- return r;
- else
- return r - (v2 < 0 ? v2 : -v2); // negative abs() [to avoid overflow]
- }
- #ifdef STB_DIVIDE_TEST
- #include <stdio.h>
- #include <math.h>
- #include <limits.h>
- int show=0;
- int err=0;
- void stbdiv_check(int q, int r, int a, int b, char *type, int dir)
- {
- if ((dir > 0 && r < 0) || (dir < 0 && r > 0)) {
- fprintf(stderr, "FAILED: %s(%d,%d) remainder %d in wrong direction\n", type,a,b,r);
- err++;
- } else
- if (b != INT_MIN) // can't compute abs(), but if b==INT_MIN all remainders are valid
- if (r <= -abs(b) || r >= abs(b)) {
- fprintf(stderr, "FAILED: %s(%d,%d) remainder %d out of range\n", type,a,b,r);
- err++;
- }
- #ifdef STB_DIVIDE_TEST_64
- {
- STB_DIVIDE_TEST_64 q64 = q, r64=r, a64=a, b64=b;
- if (q64*b64+r64 != a64) {
- fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
- err++;
- }
- }
- #else
- if (q*b+r != a) {
- fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
- err++;
- }
- #endif
- }
- void test(int a, int b)
- {
- int q,r;
- if (show) printf("(%+11d,%+d) | ", a,b);
- q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b);
- if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "trunc",a);
- q = stb_div_floor(a,b), r = stb_mod_floor(a,b);
- if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "floor",b);
- q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b);
- if (show) printf("(%+11d,%+2d)\n", q,r); stbdiv_check(q,r,a,b, "euclidean",1);
- }
- void testh(int a, int b)
- {
- int q,r;
- if (show) printf("(%08x,%08x) |\n", a,b);
- q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b); stbdiv_check(q,r,a,b, "trunc",a);
- if (show) printf(" (%08x,%08x)", q,r);
- q = stb_div_floor(a,b), r = stb_mod_floor(a,b); stbdiv_check(q,r,a,b, "floor",b);
- if (show) printf(" (%08x,%08x)", q,r);
- q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b); stbdiv_check(q,r,a,b, "euclidean",1);
- if (show) printf(" (%08x,%08x)\n ", q,r);
- }
- int main(int argc, char **argv)
- {
- if (argc > 1) show=1;
- test(8,3);
- test(8,-3);
- test(-8,3);
- test(-8,-3);
- test(1,2);
- test(1,-2);
- test(-1,2);
- test(-1,-2);
- test(8,4);
- test(8,-4);
- test(-8,4);
- test(-8,-4);
- test(INT_MAX,1);
- test(INT_MIN,1);
- test(INT_MIN+1,1);
- test(INT_MAX,-1);
- //test(INT_MIN,-1); // this traps in MSVC, so we leave it untested
- test(INT_MIN+1,-1);
- test(INT_MIN,-2);
- test(INT_MIN+1,2);
- test(INT_MIN+1,-2);
- test(INT_MAX,2);
- test(INT_MAX,-2);
- test(INT_MIN+1,2);
- test(INT_MIN+1,-2);
- test(INT_MIN,2);
- test(INT_MIN,-2);
- test(INT_MIN,7);
- test(INT_MIN,-7);
- test(INT_MIN+1,4);
- test(INT_MIN+1,-4);
- testh(-7, INT_MIN);
- testh(-1, INT_MIN);
- testh(1, INT_MIN);
- testh(7, INT_MIN);
- testh(INT_MAX-1, INT_MIN);
- testh(INT_MAX, INT_MIN);
- testh(INT_MIN, INT_MIN);
- testh(INT_MIN+1, INT_MIN);
- testh(INT_MAX-1, INT_MAX);
- testh(INT_MAX , INT_MAX);
- testh(INT_MIN , INT_MAX);
- testh(INT_MIN+1, INT_MAX);
- return err > 0 ? 1 : 0;
- }
- #endif // STB_DIVIDE_TEST
- #endif // STB_DIVIDE_IMPLEMENTATION
- #endif // INCLUDE_STB_DIVIDE_H
- /*
- ------------------------------------------------------------------------------
- This software is available under 2 licenses -- choose whichever you prefer.
- ------------------------------------------------------------------------------
- ALTERNATIVE A - MIT License
- Copyright (c) 2017 Sean Barrett
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- ------------------------------------------------------------------------------
- ALTERNATIVE B - Public Domain (www.unlicense.org)
- This is free and unencumbered software released into the public domain.
- Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
- software, either in source code form or as a compiled binary, for any purpose,
- commercial or non-commercial, and by any means.
- In jurisdictions that recognize copyright laws, the author or authors of this
- software dedicate any and all copyright interest in the software to the public
- domain. We make this dedication for the benefit of the public at large and to
- the detriment of our heirs and successors. We intend this dedication to be an
- overt act of relinquishment in perpetuity of all present and future rights to
- this software under copyright law.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- ------------------------------------------------------------------------------
- */
|