题解 UVA12413 【Big Decimal Calculator】
2024/10/10:代码重构,题解重写
你需要实现一个高精度小数类,同时支持 15 种运算,包括加减乘除,
补充条件:在新的代码下,根据 assert
返回的结果,加减法的结果并不会非常靠近
在之前的代码版本,我们实现了以十进制压位定点小数为基础的高精度小数类。这份代码在最终数据上跑了整整 210ms,这实在是太慢了,那么不妨考虑利用古法手搓一个性能稍微好一些的高精度小数类。
不妨以 Python 实现的大整数类为基础实现定点小数类。我们首先观察 Python 实现的大整数类。简单来说,一个大整数包含两个元素:
int size
告诉我们数字的大小,其中\text{size} = 0 代表这个数字就是0 ,\text{size} > 0 代表这个数字大于0 ,\text{size} < 0 代表这个数字小于0 。int *data
储存了数字的所有数位信息,其长度至少为|\text{size}| 。
Python 实现的大整数将 int
中,也就是 data[]
储存的数字是
- 在计算加减法的时候,对每一个数位,计算
a_i + b_i + \text{carry} 或者a_i - \text{borrow} - b_i 之后,可以直接通过位运算计算出当前数位的结果和进退位的值; - 在暴力乘法中,可以通过位运算在临时的答案过大的时候转移到新的变量上,详情参见代码;
- 在除法中,每次只需要除以
2 之后进行一次比较和至多一次减法,即可确定除法答案中一个 bit 的信息。
不妨将这个思路运用在小数处理上。我们最终需要保留
根据同样的思路,对于一个小数,我们只需要将其乘上 int
数组即可。同理定义 size
。在这个基础上,考虑分别处理需要实现的功能。
I/O
我们需要将一个十进制小数字符串转换为设计好的小数类,同时也需要将小数类转换为十进制字符串。
为了加速转换流程,考虑将若干个十进制数位放在一起考虑。由于
考虑 Input 部分。我们首先需要初始化数组,那么可以先获取整数部分的长度
在新建数组并初始化之后,将数组分为整数部分和小数部分,随后分别计算。
整数部分
从前往后
小数部分
我们将小数部分的字符串从前往后 0
。
随后从高到低确认小数部分的
最后可以考虑四舍五入。如果进一步计算(也就是序列乘以
随后是 Output 部分,不妨假设题目要求计算 p
位小数。我们首先将数组进行拷贝,在新数组上,分别对整数部分和小数部分操作即可。
小数部分
通过和 Input 类似的方案,每次对小数部分的数组乘上
随后考虑小数部分的最低位,如果其不小于 5
,则需要进行四舍五入,此时在字符串上不断模拟加法,直到不产生进位或者进位到整数部分。如果进位到整数部分,则需要特殊记录,并在整数部分的开始加到个位上。
整数部分
首先获得整数部分长度
在新建数组后不断对整数部分除以
最后将两部分拼接并输出即可。
基础运算
对于加减法,考虑到储存方式的特殊性,我们可以首先实现两个函数,分别计算小数绝对值的加减法(这对应 CPython 里的 x_add
和 x_sub
函数),然后在调用时进行讨论即可。
对于乘法,考虑到数组长度并不大,故直接使用暴力乘法即可。当我们计算结果的每一位时,考虑到累加乘积的时候可能会超出范围,需要使用两个辅助变量,分别代表当前计算结果和进位,在当前结果过大的时候提前计算进位。
对于除法,首先通过除数和被除数的长度估算出答案的最大可能长度,然后将除数的最高位对齐到被除数最高位的上一位,每次除以 2 后进行比较即可从高到低获得答案的二进制位。
我们可以另外实现一些乘以/除以整数的功能,以及 <<=
和 >>=
重载(对应为移动数组)。
数学运算
剩下的就是一些数学运算了。
exp
使用如下公式计算即可。本题保证答案不会超过
ln
首先,如果参数
否则,可以获取 >>=
运算符快速将其降低到
剩余的就是计算
其中
sqrt
使用牛顿迭代法即可,令
这里有一个需要注意的点:最终
pow
sin
首先处理正负性,然后将参数对
cos
同理用如下方式计算:
tan
asin
由于 asin
函数对应的级数收敛的不是很快,故可以转换为 atan
计算:
acos
使用下面的公式转换为
atan
atan
函数存在级数:
这个级数在
通过上面的公式不断迭代,直到
atan2
根据参数对应的点在平面坐标系下的位置判定即可。具体的公式可以参考其他题解或者网络资源。
在实现以上细节,并且用字符串初始化一些常量之后,我们就可以完成这道题目了。以下的代码在官方的数据中获得了 0ms 的好成绩,足以说明了以二进制为基础的高精度数字类的确可以在复杂计算中提供速度优势。
另外,你可以在 uDebug 中进行调试。这道题目中有一个较为优秀的自测数据,但是有 65 个点存在若干问题(比如答案超出了
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
namespace big {
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
struct BigDecimal {
private:
int _size;
int *_digits;
public:
static const int IDLE_DIGITS = 13;
static const int MAX_BITS = 30;
static const int MAX_VALUE = (1 << MAX_BITS);
static const int MAX_MASK = (1 << MAX_BITS) - 1;
static const int conv_width = floor(log10(MAX_VALUE - 1));
static const i64 conv_pow = pow(10, conv_width);
static const int DIG = 50;
static const int DLEN = ceil((DIG + IDLE_DIGITS) * log2(10) / MAX_BITS);
int long_size(i64 x) {
int res = 1; x = abs(x);
while (x >>= MAX_BITS)
++ res;
return res;
}
void load_long(i64 x) {
if (x == 0)
_size = 0, _digits = nullptr;
else {
_size = long_size(x) + DLEN;
_digits = new int[_size];
memset(_digits, 0, sizeof(int) * _size);
if (x < 0) _size = -_size;
int ptr = DLEN; x = abs(x);
while (x) {
_digits[ptr ++] = x & MAX_MASK;
x >>= MAX_BITS;
}
}
}
BigDecimal(): _size(0), _digits(nullptr) {}
BigDecimal(int x) { load_long(x); }
BigDecimal(i64 x) { load_long(x); }
BigDecimal(const char *str) {
bool flg = false;
if (*str == '-')
flg = true, ++ str;
const char *int_part = str;
while (*int_part != '\0' && *int_part != '.')
++ int_part;
int int_len = int_part - str;
_size = DLEN + ceil(int_len * log2(10) / MAX_BITS);
_digits = new int[_size];
memset(_digits, 0, sizeof(int) * _size);
static i64 _pow10[conv_width + 1] = {0};
if (_pow10[0] == 0) {
_pow10[0] = 1;
for (int i = 1; i <= conv_width; i ++)
_pow10[i] = _pow10[i - 1] * 10;
}
int k, cur_width = 0, top_pos = DLEN;
i64 cur_num = 0;
while (str < int_part) {
k = (*str) ^ 48;
++ cur_width;
cur_num = cur_num * 10 + k;
if ((++ str) == int_part || cur_width == conv_width) {
for (int i = DLEN; i < top_pos; i ++) {
cur_num += _pow10[cur_width] * _digits[i];
_digits[i] = cur_num & MAX_MASK;
cur_num >>= MAX_BITS;
}
while (cur_num) {
_digits[top_pos ++] = cur_num & MAX_MASK;
cur_num >>= MAX_BITS;
}
cur_width = 0;
}
}
if (*int_part == '.') {
const char *dec_part = ++ int_part;
const char *end = dec_part;
while (*end != '\0')
++ end;
if (dec_part != end) {
int dec_len = ceil((double)(end - dec_part) / conv_width);
int *assist = new int[dec_len];
memset(assist, 0, sizeof(int) * dec_len);
for (int i = 0; i < dec_len; i ++) {
for (int j = conv_width - 1; j >= 0; j --) {
if (*dec_part == '\0')
break;
assist[i] += _pow10[j] * ((*dec_part++) ^ 48);
}
}
for (int i = DLEN - 1; i >= 0; i --) {
i64 carry = 0;
for (int j = dec_len - 1; j >= 0; j --) {
carry += (i64)MAX_VALUE * assist[j];
assist[j] = carry % conv_pow;
carry /= conv_pow;
}
_digits[i] = carry;
}
if (assist[0] >= conv_pow / 2) {
for (int i = 0; i < _size; i ++) {
if (++ _digits[i] >= MAX_VALUE)
_digits[i] = 0;
else
break;
}
}
delete[] assist;
}
}
if (flg)
_size = -_size;
normalize();
}
~BigDecimal() {
delete[] _digits;
}
void copy_from_other(const BigDecimal &bd) {
_size = bd._size;
if (_digits != nullptr)
delete[] _digits, _digits = nullptr;
if (_size != 0) {
_digits = new int[abs(_size)];
memcpy(_digits, bd._digits, sizeof(int) * abs(_size));
}
}
BigDecimal(const BigDecimal &bd): _digits(nullptr) {
copy_from_other(bd);
}
BigDecimal &operator=(const BigDecimal &bd) {
if (this != &bd)
copy_from_other(bd);
return *this;
}
void swap(BigDecimal &bd) {
std::swap(_size, bd._size);
std::swap(_digits, bd._digits);
}
static BigDecimal epsilon() {
BigDecimal res;
res._size = 1;
res._digits = new int[1];
res._digits[0] = 1;
return res;
}
int size() const { return abs(_size); }
int int_size() const { return std::max(abs(_size) - DLEN, 0); }
bool is_zero() const { return _size == 0; }
bool is_nega() const { return _size < 0; }
bool is_posi() const { return _size > 0; }
void negate() { _size = -_size; }
void normalize() {
int i = size();
while (i != 0 && _digits[i - 1] == 0)
-- i;
_size = (_size >= 0 ? i : -i);
}
void align(int new_size) {
if (_size == 0)
return;
if (new_size <= 0) {
_size = 0;
delete[] _digits;
_digits = nullptr;
return;
}
int *temp = new int[new_size];
memset(temp, 0, sizeof(int) * new_size);
int valid = std::min(size(), new_size);
memcpy(temp + std::max(0, new_size - valid)
, _digits + std::max(0, size() - valid)
, sizeof(int) * valid);
if (is_nega())
new_size = -new_size;
_size = new_size;
if (_digits != nullptr)
delete[] _digits;
_digits = temp;
}
void print(int MAX_DIG = DIG) {
if (is_nega())
putchar('-');
int work_len = std::max((int)DLEN, size());
int *assist = new int[work_len + 1];
memset(assist, 0, sizeof(int) * (work_len + 1));
if (size())
memcpy(assist, _digits, sizeof(int) * size());
char *dec_result = new char[MAX_DIG + 1];
for (int i = 0; i <= MAX_DIG; i += conv_width) {
i64 carry = 0;
for (int j = 0; j < DLEN; j ++) {
carry += conv_pow * assist[j];
assist[j] = carry & MAX_MASK;
carry >>= MAX_BITS;
}
for (int j = 0; j < conv_width; j ++) {
int pos = i + conv_width - 1 - j;
if (pos <= MAX_DIG)
dec_result[pos] = ('0' + carry % 10);
carry /= 10;
}
}
if (dec_result[MAX_DIG] >= '5') {
bool carry = true;
for (int i = MAX_DIG - 1; i >= 0 && carry; i --) {
if (dec_result[i] == '9')
dec_result[i] = '0';
else
++ dec_result[i], carry = false;
}
if (carry) {
for (int i = DLEN; i <= work_len; i ++) {
if (++ assist[i] >= MAX_VALUE)
assist[i] = 0;
else
break;
}
}
}
int top_pos = work_len;
while (top_pos >= DLEN && assist[top_pos] == 0)
-- top_pos;
if (top_pos == DLEN - 1)
putchar('0');
else {
int estimate_len = ceil((top_pos - DLEN + 1) * log10(MAX_VALUE));
estimate_len = (estimate_len + conv_width - 1) / conv_width * conv_width;
char *int_result = new char[estimate_len];
for (int i = 0; i < estimate_len; i += conv_width) {
i64 carry = 0;
for (int j = top_pos; j >= (int)DLEN; j --) {
carry = (carry << MAX_BITS) ^ assist[j];
assist[j] = carry / conv_pow;
carry = carry % conv_pow;
}
while (top_pos >= DLEN && assist[top_pos] == 0)
-- top_pos;
for (int j = 0; j < conv_width; j ++)
int_result[i + j] = ('0' + carry % 10), carry /= 10;
}
bool printed = false;
for (int i = estimate_len - 1; i >= 0; i --)
if (printed |= int_result[i] != '0')
putchar(int_result[i]);
delete[] int_result;
}
putchar('.');
for (int i = 0; i < MAX_DIG; i ++)
putchar(dec_result[i]);
delete[] dec_result;
}
friend int compare(const BigDecimal &a, const BigDecimal &b) {
if (a._size != b._size)
return a._size - b._size;
for (int i = a.size() - 1; i >= 0; i --) if (a._digits[i] != b._digits[i])
return a._size > 0 ? a._digits[i] - b._digits[i] : b._digits[i] - a._digits[i];
return 0;
}
friend bool operator<(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) < 0;
}
friend bool operator>(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) > 0;
}
friend bool operator<=(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) <= 0;
}
friend bool operator>=(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) >= 0;
}
friend bool operator==(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) == 0;
}
friend bool operator!=(const BigDecimal &a, const BigDecimal &b) {
return compare(a, b) != 0;
}
void mul_num(i64 x) {
if (is_zero())
return;
if (x < 0) x = -x, negate();
int l = size();
(is_nega() ? _size -= long_size(x) : _size += long_size(x));
int *new_num = new int[size()];
u64 carry = 0, low = x & MAX_MASK, high = x >> MAX_BITS;
int i = 0;
for (; i < l; i ++) {
carry += low * _digits[i];
new_num[i] = carry & MAX_MASK;
carry >>= MAX_BITS;
carry += high * _digits[i];
}
while (carry) {
new_num[i ++] = carry & MAX_MASK;
carry >>= MAX_BITS;
}
for (; i < size(); i ++)
new_num[i] = 0;
delete[] _digits;
_digits = new_num;
normalize();
}
friend BigDecimal operator*(const BigDecimal &a, const i64 x) {
BigDecimal res = a;
res.mul_num(x);
return res;
}
friend BigDecimal operator*(const BigDecimal &a, const int x) {
BigDecimal res = a;
res.mul_num(x);
return res;
}
void div_num(i64 x) {
if (x < 0) x = -x, negate();
i64 carry = 0;
for (int i = size() - 1; i >= 0; i --) {
carry = (carry << MAX_BITS) ^ _digits[i];
_digits[i] = carry / x;
carry %= x;
}
normalize();
}
friend BigDecimal operator/(const BigDecimal &a, const i64 x) {
BigDecimal res = a;
res.div_num(x);
return res;
}
friend BigDecimal operator/(const BigDecimal &a, const int x) {
BigDecimal res = a;
res.div_num(x);
return res;
}
friend BigDecimal &operator<<=(BigDecimal &a, const int x) {
a.align(a.size() + x);
return a;
}
friend BigDecimal &operator>>=(BigDecimal &a, const int x) {
a.align(a.size() - x);
return a;
}
friend BigDecimal num_add(const BigDecimal &a, const BigDecimal &b) {
if (a.size() < b.size())
return num_add(b, a);
BigDecimal res(0);
res._size = a.size() + 1;
res._digits = new int[res._size];
int i = 0, carry = 0;
for (; i < b.size(); i ++) {
carry = carry + a._digits[i] + b._digits[i];
res._digits[i] = carry & MAX_MASK;
carry >>= MAX_BITS;
}
for (; i < a.size(); i ++) {
carry = carry + a._digits[i];
res._digits[i] = carry & MAX_MASK;
carry >>= MAX_BITS;
}
res._digits[i] = carry;
res.normalize();
return res;
}
friend BigDecimal num_sub_basic(const BigDecimal &a, const BigDecimal &b) {
BigDecimal res(0);
res._size = a.size();
res._digits = new int[res._size];
u32 borrow = 0;
int i = 0;
for (; i < b.size(); i ++) {
borrow = a._digits[i] - borrow - b._digits[i];
res._digits[i] = borrow & MAX_MASK;
borrow >>= MAX_BITS;
borrow &= 1;
}
for (; i < a.size(); i ++) {
borrow = a._digits[i] - borrow;
res._digits[i] = borrow & MAX_MASK;
borrow >>= MAX_BITS;
borrow &= 1;
}
res.normalize();
return res;
}
friend BigDecimal num_sub(const BigDecimal &a, const BigDecimal &b) {
if (a.size() > b.size())
return num_sub_basic(a, b);
if (a.size() < b.size()) {
BigDecimal res = num_sub_basic(b, a);
res.negate();
return res;
}
for (int i = a.size() - 1; i >= 0; i --) if (a._digits[i] != b._digits[i]) {
if (a._digits[i] < b._digits[i]) {
BigDecimal res = num_sub_basic(b, a);
res.negate();
return res;
}
else
return num_sub_basic(a, b);
}
return BigDecimal();
}
friend BigDecimal operator-(const BigDecimal &a) {
BigDecimal res = a;
res.negate();
return res;
}
friend BigDecimal operator+(const BigDecimal &a, const BigDecimal &b) {
if (a.is_zero())
return b;
if (b.is_zero())
return a;
if (a.is_nega()) {
if (b.is_nega()) {
BigDecimal res = num_add(a, b);
res.negate();
return res;
}
return num_sub(b, a);
}
if (b.is_nega())
return num_sub(a, b);
return num_add(a, b);
}
friend BigDecimal operator-(const BigDecimal &a, const BigDecimal &b) {
if (a.is_zero())
return - b;
if (b.is_zero())
return a;
if (a.is_nega()) {
BigDecimal res = (b.is_nega()? num_sub(a, b) : num_add(a, b));
res.negate();
return res;
}
if (b.is_nega())
return num_add(a, b);
return num_sub(a, b);
}
friend BigDecimal operator*(const BigDecimal &a, const BigDecimal &b) {
if (a.size() == 0 || b.size() == 0)
return BigDecimal();
BigDecimal res(0);
res._size = std::max(0, a.size() + b.size() - a.DLEN) + 1;
res._digits = new int[res._size];
i64 current = 0, carry = 0;
for (int tot = - a.DLEN; tot < res._size; tot ++) {
for (int i = std::max(tot + a.DLEN - b.size() + 1, 0); i < a.size() && i <= tot + a.DLEN; i ++) {
current += (i64)a._digits[i] * b._digits[tot + a.DLEN - i];
if (current >> 60) {
carry += current >> MAX_BITS;
current &= MAX_MASK;
}
}
carry += current >> MAX_BITS;
current &= MAX_MASK;
if (tot >= 0)
res._digits[tot] = current;
current = carry;
carry = 0;
}
if (a.is_nega() ^ b.is_nega())
res.negate();
res.normalize();
return res;
}
void div2() {
int carry = 0;
for (int i = size() - 1; i >= 0; i --) {
carry = (carry << MAX_BITS) ^ _digits[i];
_digits[i] = carry >> 1;
carry &= 1;
}
normalize();
}
friend BigDecimal operator/(const BigDecimal &a, const BigDecimal &b) {
if (a.is_zero())
return BigDecimal();
BigDecimal ta = a, tb = b, res(0);
int len = ta.size() - tb.size() + a.DLEN + 1;
if (len <= 0)
return res;
res._size = len;
res._digits = new int[len];
ta._size = abs(ta._size);
tb._size = abs(tb._size);
tb.align(ta.size() + 1);
for (int i = len - 1; i >= 0; i --) {
int num = 0;
for (int j = 0; j < MAX_BITS; j ++) {
tb.div2(); num <<= 1;
if (ta >= tb) {
ta = num_sub(ta, tb);
num ^= 1;
}
}
res._digits[i] = num;
}
if (a.is_nega() ^ b.is_nega())
res.negate();
res.normalize();
return res;
}
BigDecimal integer() const {
BigDecimal res = *this;
for (int i = 0; i < DLEN && i < size(); i ++)
res._digits[i] = 0;
res.normalize();
return res;
}
BigDecimal decimal() const {
if (is_zero())
return BigDecimal();
int nlen = std::min(DLEN, size());
BigDecimal res(0);
res._size = nlen;
res._digits = new int[nlen];
memcpy(res._digits, _digits, sizeof(int) * nlen);
if (is_nega())
res.negate();
return res;
}
friend BigDecimal abs(BigDecimal x) {
x._size = std::abs(x._size);
return x;
}
};
const BigDecimal _ln2("0.693147180559945309417232121458176568075500134360255254120680");
const BigDecimal _pi("3.141592653589793238462643383279502884197169399375105820974944");
const BigDecimal _sqrt2("1.414213562373095048801688724209698078569671875376948073176680");
const BigDecimal _one("1");
const BigDecimal _pi_2 = _pi * 2;
const BigDecimal _pi_half = _pi / 2;
const BigDecimal _eps = BigDecimal::epsilon();
BigDecimal exp(BigDecimal x) {
BigDecimal ans = 1, cnt = 1;
for (int i = 1; ; i ++) {
cnt = cnt * x / i;
if (cnt.is_zero())
break;
ans = ans + cnt;
}
return ans;
}
BigDecimal sqrt(BigDecimal x) {
BigDecimal cur = x, las = 0;
do {
las.swap(cur);
cur = (las + x / las) / 2;
} while (abs(cur - las) > _eps);
return cur;
}
BigDecimal ln(BigDecimal x) {
if (x < _one)
return -ln(_one / x);
BigDecimal coef = 0;
int num = x.int_size();
if (num > 1)
x >>= num - 1, coef = _ln2 * ((long long)(num - 1) * x.MAX_BITS);
while (x > _sqrt2)
x.div2(), coef = coef + _ln2;
x = (x - _one) / (x + _one);
BigDecimal cnt = x * 2, res = cnt;
x = x * x;
for (int i = 3; ; i += 2) {
cnt = cnt * x;
BigDecimal p = cnt / i;
if (p.is_zero())
break;
res = res + p;
}
return res + coef;
}
BigDecimal pow(BigDecimal a, BigDecimal x) {
return exp(ln(a) * x);
}
BigDecimal sin(BigDecimal x) {
if (x.is_nega())
return -sin(-x);
if (x >= _pi_2)
x = x - (x / _pi_2).integer() * _pi_2;
BigDecimal res = x, cur = x;
x = x * x;
for (long long i = 3; ; i += 2) {
cur = cur * x / (i * (i - 1));
if (cur.is_zero())
break;
cur.negate();
res = res + cur;
}
return res;
}
BigDecimal cos(BigDecimal x) {
if (x.is_nega())
return cos(-x);
if (x >= _pi_2)
x = x - (x / _pi_2).integer() * _pi_2;
BigDecimal res = 1, cur = 1;
x = x * x;
for (long long i = 2; ; i += 2) {
cur = cur * x / BigDecimal(i * (i - 1));
cur.negate();
if (cur.is_zero())
break;
res = res + cur;
}
return res;
}
BigDecimal tan(BigDecimal x) {
return sin(x) / cos(x);
}
BigDecimal atan(BigDecimal x) {
static BigDecimal comp("0.1");
if (x.is_nega())
return - atan(-x);
if (x > _one)
return _pi_half - atan(_one / x);
if (x >= comp)
return atan((sqrt(_one + x * x) - _one) / x) * 2;
BigDecimal cnt = x, res = x;
x = x * x; x.negate();
for (int i = 3; ; i += 2) {
cnt = cnt * x;
BigDecimal p = cnt / i;
if (p.is_zero())
break;
res = res + p;
}
return res;
}
BigDecimal asin(BigDecimal x) {
return atan(x / sqrt(_one - x * x));
}
BigDecimal acos(BigDecimal x) {
return _pi_half - asin(x);
}
BigDecimal atan2(BigDecimal y, BigDecimal x) {
if (x.is_posi())
return atan(y / x);
if (x.is_zero()) {
if (y.is_nega())
return - _pi_half;
return _pi_half;
}
if (y.is_nega())
return atan(y / x) - _pi;
return atan(y / x) + _pi;
}
}
using namespace big;
void read(BigDecimal &bd) {
static char ch[110];
scanf("%s", ch);
bd = ch;
}
BigDecimal a, b;
char op[10];
int main() {
while (scanf("%s", op) != EOF) {
if (strcmp(op, "add") == 0) {
read(a); read(b); a = a + b;
}
else if (strcmp(op, "sub") == 0) {
read(a); read(b); a = a - b;
}
else if (strcmp(op, "mul") == 0) {
read(a); read(b); a = a * b;
}
else if (strcmp(op, "div") == 0) {
read(a); read(b); a = a / b;
}
else if (strcmp(op, "pow") == 0) {
read(a); read(b); a = pow(a, b);
}
else if (strcmp(op, "atan2") == 0) {
read(a); read(b); a = atan2(a, b);
}
else if (strcmp(op, "exp") == 0) {
read(a); a = exp(a);
}
else if (strcmp(op, "ln") == 0) {
read(a); a = ln(a);
}
else if (strcmp(op, "sqrt") == 0) {
read(a); a = sqrt(a);
}
else if (strcmp(op, "sin") == 0) {
read(a); a = sin(a);
}
else if (strcmp(op, "cos") == 0) {
read(a); a = cos(a);
}
else if (strcmp(op, "tan") == 0) {
read(a); a = tan(a);
}
else if (strcmp(op, "asin") == 0) {
read(a); a = asin(a);
}
else if (strcmp(op, "acos") == 0) {
read(a); a = acos(a);
}
else if (strcmp(op, "atan") == 0) {
read(a); a = atan(a);
}
else {
break;
}
int prec; scanf("%d", &prec);
a.print(prec); puts("");
}
return 0;
}