📄 erl_arith.c
字号:
do_big: sz1 = big_size(arg1); sz2 = big_size(arg2); sz = MAX(sz1, sz2)+1; need_heap = BIG_NEED_SIZE(sz); hp = ArithAlloc(p, need_heap); res = big_minus(arg1, arg2, hp); if (is_nil(res)) { erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } maybe_shrink(p, hp, res, need_heap); ArithCheck(p); return res; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): goto do_big; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { goto badarith; } GET_DOUBLE(arg2, f2); goto do_float; default: goto badarith; } } case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); f2.fd = signed_val(arg2); goto do_float; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); if (big_to_double(arg2, &f2.fd) < 0) { goto badarith; } goto do_float; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); GET_DOUBLE(arg2, f2); do_float: f1.fd = f1.fd - f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); hp = ArithAlloc(p, FLOAT_SIZE_OBJECT); res = make_float(hp); ArithCheck(p); PUT_DOUBLE(f1, hp); return res; default: goto badarith; } default: goto badarith; } } default: goto badarith; }}Etermerts_mixed_times(Process* p, Eterm arg1, Eterm arg2){ Eterm tmp_big1[2]; Eterm tmp_big2[2]; Eterm hdr; Eterm res; FloatDef f1, f2; dsize_t sz1, sz2, sz; int need_heap; Eterm* hp; ERTS_FP_CHECK_INIT(p); switch (arg1 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): if ((arg1 == SMALL_ZERO) || (arg2 == SMALL_ZERO)) { return(SMALL_ZERO); } else if (arg1 == SMALL_ONE) { return(arg2); } else if (arg2 == SMALL_ONE) { return(arg1); } else { Eterm big_res[3]; /* * The following code is optimized for the case that * result is small (which should be the most common case * in practice). */ arg1 = small_to_big(signed_val(arg1), tmp_big1); arg2 = small_to_big(signed_val(arg2), tmp_big2); res = big_times(arg1, arg2, big_res); if (is_small(res)) { return res; } else { /* * The result is a a big number. * Allocate a heap fragment and copy the result. * Be careful to allocate exactly what we need * to not leave any holes. */ Uint arity; ASSERT(is_big(res)); hdr = big_res[0]; arity = bignum_header_arity(hdr); ASSERT(arity == 1 || arity == 2); hp = ArithAlloc(p, arity+1); res = make_big(hp); *hp++ = hdr; *hp++ = big_res[1]; if (arity > 1) { *hp = big_res[2]; } return res; } } default: badarith: p->freason = BADARITH; return THE_NON_VALUE; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): if (arg1 == SMALL_ZERO) return(SMALL_ZERO); if (arg1 == SMALL_ONE) return(arg2); arg1 = small_to_big(signed_val(arg1), tmp_big1); sz = 2 + big_size(arg2); goto do_big; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): f1.fd = signed_val(arg1); GET_DOUBLE(arg2, f2); goto do_float; default: goto badarith; } } default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg1); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): if (arg2 == SMALL_ZERO) return(SMALL_ZERO); if (arg2 == SMALL_ONE) return(arg1); arg2 = small_to_big(signed_val(arg2), tmp_big2); sz = 2 + big_size(arg1); goto do_big; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): sz1 = big_size(arg1); sz2 = big_size(arg2); sz = sz1 + sz2; do_big: need_heap = BIG_NEED_SIZE(sz); hp = ArithAlloc(p, need_heap); res = big_times(arg1, arg2, hp); /* * Note that the result must be big in this case, since * at least one operand was big to begin with, and * the absolute value of the other is > 1. */ if (is_nil(res)) { erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } maybe_shrink(p, hp, res, need_heap); ArithCheck(p); return res; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { goto badarith; } GET_DOUBLE(arg2, f2); goto do_float; default: goto badarith; } } case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); f2.fd = signed_val(arg2); goto do_float; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); if (big_to_double(arg2, &f2.fd) < 0) { goto badarith; } goto do_float; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); GET_DOUBLE(arg2, f2); do_float: f1.fd = f1.fd * f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); hp = ArithAlloc(p, FLOAT_SIZE_OBJECT); res = make_float(hp); ArithCheck(p); PUT_DOUBLE(f1, hp); return res; default: goto badarith; } default: goto badarith; } } default: goto badarith; }}Etermerts_mixed_div(Process* p, Eterm arg1, Eterm arg2){ FloatDef f1, f2; Eterm* hp; Eterm hdr; ERTS_FP_CHECK_INIT(p); switch (arg1 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg1 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): f1.fd = signed_val(arg1); f2.fd = signed_val(arg2); goto do_float; default: badarith: p->freason = BADARITH; return THE_NON_VALUE; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): f1.fd = signed_val(arg1); if (big_to_double(arg2, &f2.fd) < 0) { goto badarith; } goto do_float; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): f1.fd = signed_val(arg1); GET_DOUBLE(arg2, f2); goto do_float; default: goto badarith; } } default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg1); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { goto badarith; } f2.fd = signed_val(arg2); goto do_float; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0 || big_to_double(arg2, &f2.fd) < 0) { goto badarith; } goto do_float; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): if (big_to_double(arg1, &f1.fd) < 0) { goto badarith; } GET_DOUBLE(arg2, f2); goto do_float; default: goto badarith; } } case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): switch (arg2 & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: switch ((arg2 & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); f2.fd = signed_val(arg2); goto do_float; default: goto badarith; } case TAG_PRIMARY_BOXED: hdr = *boxed_val(arg2); switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); if (big_to_double(arg2, &f2.fd) < 0) { goto badarith; } goto do_float; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): GET_DOUBLE(arg1, f1); GET_DOUBLE(arg2, f2); do_float: f1.fd = f1.fd / f2.fd; ERTS_FP_ERROR(p, f1.fd, goto badarith); hp = ArithAlloc(p, FLOAT_SIZE_OBJECT); PUT_DOUBLE(f1, hp); ArithCheck(p); return make_float(hp); default: goto badarith; } default: goto badarith; } } default: goto badarith; }}Etermerts_int_div(Process* p, Eterm arg1, Eterm arg2){ Eterm tmp_big1[2]; Eterm tmp_big2[2]; int ires; switch (NUMBER_CODE(arg1, arg2)) { case SMALL_SMALL: /* This case occurs if the most negative fixnum is divided by -1. */ ASSERT(arg2 == make_small(-1)); arg1 = small_to_big(signed_val(arg1), tmp_big1); /*FALLTHROUGH*/ case BIG_SMALL: arg2 = small_to_big(signed_val(arg2), tmp_big2); goto L_big_div; case SMALL_BIG: if (arg1 != make_small(MIN_SMALL)) { return SMALL_ZERO; } arg1 = small_to_big(signed_val(arg1), tmp_big1); /*FALLTHROUGH*/ case BIG_BIG: L_big_div: ires = big_ucomp(arg1, arg2); if (ires < 0) { arg1 = SMALL_ZERO; } else if (ires == 0) { arg1 = (big_sign(arg1) == big_sign(arg2)) ? SMALL_ONE : SMALL_MINUS_ONE; } else { Eterm* hp; int i = big_size(arg1); Uint need; ires = big_size(arg2); need = BIG_NEED_SIZE(i-ires+1) + BIG_NEED_SIZE(i); hp = ArithAlloc(p, need); arg1 = big_div(arg1, arg2, hp); if (is_nil(arg1)) { erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } maybe_shrink(p, hp, arg1, need); ArithCheck(p); } return arg1; default: p->freason = BADARITH; return THE_NON_VALUE; }}Etermerts_int_rem(Process* p, Eterm arg1, Eterm arg2){ Eterm tmp_big1[2]; Eterm tmp_big2[2]; int ires; switch (NUMBER_CODE(arg1, arg2)) { case BIG_SMALL: arg2 = small_to_big(signed_val(arg2), tmp_big2); goto L_big_rem; case SMALL_BIG: if (arg1 != make_small(MIN_SMALL)) { return arg1; } arg1 = small_to_big(signed_val(arg1), tmp_big1); /*FALLTHROUGH*/ case BIG_BIG: L_big_rem: ires = big_ucomp(arg1, arg2); if (ires == 0) { arg1 = SMALL_ZERO; } else if (ires > 0) { Uint need = BIG_NEED_SIZE(big_size(arg1)); Eterm* hp = ArithAlloc(p, need); arg1 = big_rem(arg1, arg2, hp); if (is_nil(arg1)) { erts_arith_shrink(p, hp); p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } maybe_shrink(p, hp, arg1, need); ArithCheck(p); } return arg1; default: p->freason = BADARITH; return THE_NON_VALUE; }}Eterm erts_band(Process* p, Eterm arg1, Eterm arg2){ Eterm tmp_big1[2]; Eterm tmp_big2[2]; Eterm* hp; int need; switch (NUMBER_CODE(arg1, arg2)) { case SMALL_BIG: arg1 = small_to_big(signed_val(arg1), tmp_big1); break; case BIG_SMALL: arg2 = small_to_big(signed_val(arg2), tmp_big2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -