Commit 2e2e15ce authored by Doug Currie's avatar Doug Currie Committed by Damien George
Browse files

py/mpz: Complete implementation of mpz_{and,or,xor} for negative args.

For these 3 bitwise operations there are now fast functions for
positive-only arguments, and general functions for arbitrary sign
arguments (the fast functions are the existing implementation).

By default the fast functions are not used (to save space) and instead
the general functions are used for all operations.

Enable MICROPY_OPT_MPZ_BITWISE to use the fast functions for positive
arguments.
parent 5f3e005b
......@@ -342,6 +342,12 @@
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#endif
// Whether to use fast versions of bitwise operations (and, or, xor) when the
// arguments are both positive. Increases Thumb2 code size by about 250 bytes.
#ifndef MICROPY_OPT_MPZ_BITWISE
#define MICROPY_OPT_MPZ_BITWISE (0)
#endif
/*****************************************************************************/
/* Python internal features */
......
......@@ -29,9 +29,6 @@
#include "py/mpz.h"
// this is only needed for mp_not_implemented, which should eventually be removed
#include "py/runtime.h"
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
#define DIG_SIZE (MPZ_DIG_SIZE)
......@@ -199,6 +196,14 @@ STATIC mp_uint_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen,
return idig + 1 - oidig;
}
STATIC mp_uint_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {
for (--idig; idig >= oidig && *idig == 0; --idig) {
}
return idig + 1 - oidig;
}
#if MICROPY_OPT_MPZ_BITWISE
/* computes i = j & k
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed)
......@@ -211,41 +216,46 @@ STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t
*idig = *jdig & *kdig;
}
// remove trailing zeros
for (--idig; idig >= oidig && *idig == 0; --idig) {
}
return idig + 1 - oidig;
return mpn_remove_trailing_zeros(oidig, idig);
}
/* computes i = j & -k = j & (~k + 1)
#endif
/* i = -((-j) & (-k)) = ~((~j + 1) & (~k + 1)) + 1
i = (j & (-k)) = (j & (~k + 1)) = ( j & (~k + 1))
i = ((-j) & k) = ((~j + 1) & k) = ((~j + 1) & k )
computes general form:
i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic where Xm = Xc == 0 ? 0 : DIG_MASK
returns number of digits in i
assumes enough memory in i; assumes normalised j, k
assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
can have i, j, k pointing to same memory
*/
STATIC mp_uint_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
STATIC mp_uint_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = 1;
mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
carry += *kdig ^ DIG_MASK;
*idig = (*jdig & carry) & DIG_MASK;
carry >>= DIG_SIZE;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj & carryk) ^ imask) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
for (; jlen > 0; --jlen, ++idig, ++jdig) {
carry += DIG_MASK;
*idig = (*jdig & carry) & DIG_MASK;
carry >>= DIG_SIZE;
}
// remove trailing zeros
for (--idig; idig >= oidig && *idig == 0; --idig) {
if (0 != carryi) {
*idig++ = carryi;
}
return idig + 1 - oidig;
return mpn_remove_trailing_zeros(oidig, idig);
}
#if MICROPY_OPT_MPZ_BITWISE
/* computes i = j | k
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
......@@ -267,6 +277,74 @@ STATIC mp_uint_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen,
return idig - oidig;
}
#endif
/* i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1
i = -(j | (-k)) = -(j | (~k + 1)) = ~( j | (~k + 1)) + 1
i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k ) + 1
computes general form:
i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
can have i, j, k pointing to same memory
*/
#if MICROPY_OPT_MPZ_BITWISE
STATIC mp_uint_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carryi = 1;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
if (0 != carryi) {
*idig++ = carryi;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
#else
STATIC mp_uint_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig ^ jmask;
carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask;
carryi += ((carryj | carryk) ^ imask) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
if (0 != carryi) {
*idig++ = carryi;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
#endif
#if MICROPY_OPT_MPZ_BITWISE
/* computes i = j ^ k
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
......@@ -285,11 +363,39 @@ STATIC mp_uint_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen,
*idig = *jdig;
}
// remove trailing zeros
for (--idig; idig >= oidig && *idig == 0; --idig) {
return mpn_remove_trailing_zeros(oidig, idig);
}
#endif
/* i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1)
i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1
i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1
computes general form:
i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes length j >= length k
can have i, j, k pointing to same memory
*/
STATIC mp_uint_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen,
mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
mpz_dig_t *oidig = idig;
for (; jlen > 0; ++idig, ++jdig) {
carryj += *jdig + DIG_MASK;
carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK;
carryi += (carryj ^ carryk) & DIG_MASK;
*idig = carryi & DIG_MASK;
carryk >>= DIG_SIZE;
carryj >>= DIG_SIZE;
carryi >>= DIG_SIZE;
}
return idig + 1 - oidig;
if (0 != carryi) {
*idig++ = carryi;
}
return mpn_remove_trailing_zeros(oidig, idig);
}
/* computes i = i * d1 + d2
......@@ -1097,81 +1203,106 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
can have dest, lhs, rhs the same
*/
void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
if (lhs->neg == rhs->neg) {
if (lhs->neg == 0) {
// make sure lhs has the most digits
if (lhs->len < rhs->len) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
// do the and'ing
mpz_need_dig(dest, rhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
dest->neg = 0;
} else {
// TODO both args are negative
mp_not_implemented("bignum and with negative args");
}
// make sure lhs has the most digits
if (lhs->len < rhs->len) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
#if MICROPY_OPT_MPZ_BITWISE
if ((0 == lhs->neg) && (0 == rhs->neg)) {
mpz_need_dig(dest, lhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
dest->neg = 0;
} else {
// args have different sign
// make sure lhs is the positive arg
if (rhs->neg == 0) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
mpz_need_dig(dest, lhs->len + 1);
dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
assert(dest->len <= dest->alloc);
dest->neg = 0;
dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
dest->neg = lhs->neg & rhs->neg;
}
#else
mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
(lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
dest->neg = lhs->neg & rhs->neg;
#endif
}
/* computes dest = lhs | rhs
can have dest, lhs, rhs the same
*/
void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
// make sure lhs has the most digits
if (lhs->len < rhs->len) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
if (lhs->neg == rhs->neg) {
#if MICROPY_OPT_MPZ_BITWISE
if ((0 == lhs->neg) && (0 == rhs->neg)) {
mpz_need_dig(dest, lhs->len);
dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
dest->neg = 0;
} else {
mpz_need_dig(dest, lhs->len);
// TODO
mp_not_implemented("bignum or with negative args");
// dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
mpz_need_dig(dest, lhs->len + 1);
dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
0 != lhs->neg, 0 != rhs->neg);
dest->neg = 1;
}
dest->neg = lhs->neg;
#else
mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
(lhs->neg || rhs->neg), lhs->neg, rhs->neg);
dest->neg = lhs->neg | rhs->neg;
#endif
}
/* computes dest = lhs ^ rhs
can have dest, lhs, rhs the same
*/
void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
// make sure lhs has the most digits
if (lhs->len < rhs->len) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
#if MICROPY_OPT_MPZ_BITWISE
if (lhs->neg == rhs->neg) {
mpz_need_dig(dest, lhs->len);
dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
if (lhs->neg == 0) {
dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
} else {
dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0);
}
dest->neg = 0;
} else {
mpz_need_dig(dest, lhs->len);
// TODO
mp_not_implemented("bignum xor with negative args");
// dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
mpz_need_dig(dest, lhs->len + 1);
dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
0 == lhs->neg, 0 == rhs->neg);
dest->neg = 1;
}
dest->neg = 0;
#else
mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
(lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
dest->neg = lhs->neg ^ rhs->neg;
#endif
}
/* computes dest = lhs * rhs
......
......@@ -46,6 +46,7 @@
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_OPT_MPZ_BITWISE (1)
// fatfs configuration used in ffconf.h
#define MICROPY_FATFS_ENABLE_LFN (1)
......
......@@ -26,3 +26,120 @@ print((-a) & 0xffffffff)
print((-a) & 0xffffffffffffffffffffffffffffffff)
print((-a) & 2)
print((-(1 << 70)) & 2)
# test negative on lhs and rhs
mpz = 1 << 70
a = 123456789012345678901234567890
print(-1 & (-a))
print(-2 & (-a))
print(-2345678901234567890123456789 & (-a))
print((-a) & (-a))
print((-a) & (-0xffffffff))
print((-a) & (-0xffffffffffffffffffffffffffffffff))
print((-1) & (-0xffffffffffffffffffffffffffffffff))
print((-a) & (-2))
print((-mpz) & (-2))
# test + +
print( 97989513389222316022151446562729620153292831887555425160965597396
& 23716683549865351578586448630079789776107310103486834795830390982)
print( 53817081128841898634258263553430908085326601592682411889506742059
& 37042558948907407488299113387826240429667200950043601129661240876)
print( 26167512042587370698808974207700979337713004510730289760097826496
& 98456276326770292376138852628141531773120376436197321310863125849)
print( 21085380307304977067262070503651827226504797285572981274069266136
& 15928222825828272388778130358888206480162413547887287646273147570)
print( 40827393422334167255488276244226338235131323044408420081160772273
& 63815443187857978125545555033672525708399848575557475462799643340)
print( 5181013159871685724135944379095645225188360725917119022722046448
& 59734090450462480092384049604830976376887859531148103803093112493)
print( 283894311
& 86526825689187217371383854139783231460931720533100376593106943447)
print( 40019818573920230246248826511203818792007462193311949166285967147
& 9487909752)
# test - +
print( -97989513389222316022151446562729620153292831887555425160965597396
& 23716683549865351578586448630079789776107310103486834795830390982)
print( -53817081128841898634258263553430908085326601592682411889506742059
& 37042558948907407488299113387826240429667200950043601129661240876)
print( -26167512042587370698808974207700979337713004510730289760097826496
& 98456276326770292376138852628141531773120376436197321310863125849)
print( -21085380307304977067262070503651827226504797285572981274069266136
& 15928222825828272388778130358888206480162413547887287646273147570)
print( -40827393422334167255488276244226338235131323044408420081160772273
& 63815443187857978125545555033672525708399848575557475462799643340)
print( -5181013159871685724135944379095645225188360725917119022722046448
& 59734090450462480092384049604830976376887859531148103803093112493)
print( -283894311
& 86526825689187217371383854139783231460931720533100376593106943447)
print( -40019818573920230246248826511203818792007462193311949166285967147
& 9487909752)
# test + -
print( 97989513389222316022151446562729620153292831887555425160965597396
& -23716683549865351578586448630079789776107310103486834795830390982)
print( 53817081128841898634258263553430908085326601592682411889506742059
& -37042558948907407488299113387826240429667200950043601129661240876)
print( 26167512042587370698808974207700979337713004510730289760097826496
& -98456276326770292376138852628141531773120376436197321310863125849)
print( 21085380307304977067262070503651827226504797285572981274069266136
& -15928222825828272388778130358888206480162413547887287646273147570)
print( 40827393422334167255488276244226338235131323044408420081160772273
& -63815443187857978125545555033672525708399848575557475462799643340)
print( 5181013159871685724135944379095645225188360725917119022722046448
& -59734090450462480092384049604830976376887859531148103803093112493)
print( 283894311
& -86526825689187217371383854139783231460931720533100376593106943447)
print( 40019818573920230246248826511203818792007462193311949166285967147
& -9487909752)
# test - -
print( -97989513389222316022151446562729620153292831887555425160965597396
& -23716683549865351578586448630079789776107310103486834795830390982)
print( -53817081128841898634258263553430908085326601592682411889506742059
& -37042558948907407488299113387826240429667200950043601129661240876)
print( -26167512042587370698808974207700979337713004510730289760097826496
& -98456276326770292376138852628141531773120376436197321310863125849)
print( -21085380307304977067262070503651827226504797285572981274069266136
& -15928222825828272388778130358888206480162413547887287646273147570)
print( -40827393422334167255488276244226338235131323044408420081160772273
& -63815443187857978125545555033672525708399848575557475462799643340)
print( -5181013159871685724135944379095645225188360725917119022722046448
& -59734090450462480092384049604830976376887859531148103803093112493)
print( -283894311
& -86526825689187217371383854139783231460931720533100376593106943447)
print( -40019818573920230246248826511203818792007462193311949166285967147
& -9487909752)
......@@ -2,3 +2,143 @@ print(0 | (1 << 80))
a = 0xfffffffffffffffffffffffffffff
print(a | (1 << 200))
# test + +
print(0 | (1 << 80))
print((1 << 80) | (1 << 80))
print((1 << 80) | 0)
a = 0xfffffffffffffffffffffffffffff
print(a | (1 << 100))
print(a | (1 << 200))
print(a | a == 0)
print(bool(a | a))
print( 97989513389222316022151446562729620153292831887555425160965597396
| 23716683549865351578586448630079789776107310103486834795830390982)
print( 53817081128841898634258263553430908085326601592682411889506742059
| 37042558948907407488299113387826240429667200950043601129661240876)
print( 26167512042587370698808974207700979337713004510730289760097826496
| 98456276326770292376138852628141531773120376436197321310863125849)
print( 21085380307304977067262070503651827226504797285572981274069266136
| 15928222825828272388778130358888206480162413547887287646273147570)
print( 40827393422334167255488276244226338235131323044408420081160772273
| 63815443187857978125545555033672525708399848575557475462799643340)
print( 5181013159871685724135944379095645225188360725917119022722046448
| 59734090450462480092384049604830976376887859531148103803093112493)
print( 283894311
| 86526825689187217371383854139783231460931720533100376593106943447)
print( 40019818573920230246248826511203818792007462193311949166285967147
| 9487909752)
# test - +
print((-1 << 80) | (1 << 80))
print((-1 << 80) | 0)
print((-a) | (1 << 100))
print((-a) | (1 << 200))
print((-a) | a == 0)
print(bool((-a) | a))
print( -97989513389222316022151446562729620153292831887555425160965597396
| 23716683549865351578586448630079789776107310103486834795830390982)
print( -53817081128841898634258263553430908085326601592682411889506742059
| 37042558948907407488299113387826240429667200950043601129661240876)
print( -26167512042587370698808974207700979337713004510730289760097826496
| 98456276326770292376138852628141531773120376436197321310863125849)
print( -21085380307304977067262070503651827226504797285572981274069266136
| 15928222825828272388778130358888206480162413547887287646273147570)
print( -40827393422334167255488276244226338235131323044408420081160772273
| 63815443187857978125545555033672525708399848575557475462799643340)
print( -5181013159871685724135944379095645225188360725917119022722046448
| 59734090450462480092384049604830976376887859531148103803093112493)
print( -283894311
| 86526825689187217371383854139783231460931720533100376593106943447)
print( -40019818573920230246248826511203818792007462193311949166285967147
| 9487909752)
# test + -
print(0 | (-1 << 80))
print((1 << 80) | (-1 << 80))
print(a | (-1 << 100))
print(a | (-1 << 200))
print(a | (-a) == 0)
print(bool(a | (-a)))
print( 97989513389222316022151446562729620153292831887555425160965597396
| -23716683549865351578586448630079789776107310103486834795830390982)
print( 53817081128841898634258263553430908085326601592682411889506742059
| -37042558948907407488299113387826240429667200950043601129661240876)
print( 26167512042587370698808974207700979337713004510730289760097826496
| -98456276326770292376138852628141531773120376436197321310863125849)
print( 21085380307304977067262070503651827226504797285572981274069266136
| -15928222825828272388778130358888206480162413547887287646273147570)
print( 40827393422334167255488276244226338235131323044408420081160772273
| -63815443187857978125545555033672525708399848575557475462799643340)
print( 5181013159871685724135944379095645225188360725917119022722046448
| -59734090450462480092384049604830976376887859531148103803093112493)
print( 283894311
| -86526825689187217371383854139783231460931720533100376593106943447)
print( 40019818573920230246248826511203818792007462193311949166285967147
| -9487909752)