千里马:像 Excel 中的圆形
Maxima: Round like in Excel
是否有像 Excel
中的 round()
那样对数字(甚至十进制数)进行四舍五入的函数?
例子
将 1,45 舍入到一位小数:1,5
将 2,45 舍入到一位小数:2,5
有一个 similar question 但他们使用不同的算法。
四舍五入的问题实际上非常微妙,但我认为这里有一个简单的方法可以提供可行的结果。我在这里定义了一个新函数 myround
,它具有 Excel =ROUND
所描述的行为。 [1]
(%i4) myround (x, n) := round(x*10^n)/10.0^n;
n
'round(x 10 )
(%o4) myround(x, n) := -------------
n
10.0
(%i5) myround (2.15, 1);
(%o5) 2.2
(%i6) myround (2.149, 1);
(%o6) 2.1
(%i7) myround (-1.475, 2);
(%o7) - 1.48
(%i8) myround (21.5, -1);
(%o8) 20.0
(%i9) myround (626.3, -3);
(%o9) 1000.0
(%i10) myround (1.98, -1);
(%o10) 0.0
(%i11) myround (-50.55, -2);
(%o11) - 100.0
[1] https://support.microsoft.com/en-us/office/round-function-c018c5d8-40fb-4053-90b1-b3e7f61a213c
好的,这是在 Maxima 中重新实现 Excel =ROUND 函数的尝试。一些笔记。 (1) 在应用用户舍入之前,值四舍五入到 15 位有效数字。这是为了解决因小数不准确表示为浮点数而导致的问题。 (2) 我已经将 excel_round
和 integer_log10
实现为所谓的简化函数。这意味着直到参数是可以评估的东西(在这种情况下,当参数是数字时)才会执行计算。 (3) 我没有检查 Excel =ROUND 对负数的作用——它是向上舍入 5(即在这种情况下朝零)还是远离零?我不知道。
我已将此解决方案作为小包 excel_round.mac
发布在 Github 上。请参阅:https://github.com/maxima-project-on-github/maxima-packages 并导航至 robert-dodier/excel_round
。为了完整起见,我也在这里粘贴了代码。
这里有几个例子。
(%i1) excel_round (1.15, 1);
(%o1) 1.2
(%i2) excel_round (1.25, 1);
(%o2) 1.3
(%i3) excel_round (12.455, 2);
(%o3) 12.46
(%i4) excel_round (x, 2);
(%o4) excel_round(x, 2)
(%i5) ev (%, x = 9.865);
(%o5) 9.87
这是代码。这是excel_round.mac
.
的内容
/* excel_round -- round to specified number of decimal places,
* rounding termminal 5 upwards, as in MS Excel, apparently.
* Inspired by:
*
* copyright 2020 by Robert Dodier
* I release this work under terms of the GNU General Public License.
*/
matchdeclare (xx, numberp);
matchdeclare (nn, integerp);
tellsimpafter (excel_round (xx, nn), excel_round_numerical (xx, nn));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v))));
tellsimpafter (excel_round (xx, nn), excel_round_numerical (ev (xx, numer), nn));
excel_round_numerical (x, n) :=
block ([r, r1, r2, l],
/* rationalize returns exact rational equivalent of float */
r: rationalize (x),
/* First round to 15 significant decimal places.
* This is a heuristic to recover what a user "meant"
* to type in, since many decimal numbers are not
* exactly representable as floats.
*/
l: integer_log10 (abs (r)),
r1: round (r*10^(15 - l)),
/* Now begin rounding to n places. */
r2: r1/10^((15 - l) - n),
/* If terminal digit is 5, then r2 is integer + 1/2.
* If that's the case, round upwards and rescale,
* otherwise, terminal digit is something other than 5,
* round to nearest integer and rescale.
*/
if equal (r2 - floor(r2), 1/2)
then ceiling(r2)/10.0^n
else round(r2)/10.0^n);
matchdeclare (xx, lambda ([e], numberp(e) and e > 0));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (xx));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v) and v > 0)));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (ev (xx, numer)));
matchdeclare (xx, lambda ([e], not atom(e) and op(e) = "/" and numberp (denom (e)) and pow10p (denom (e))));
pow10p (e) := integerp(e) and e > 1 and (e = 10 or pow10p (e/10));
tellsimpafter (integer_log10 (xx), integer_log10 (num (xx)) - integer_log10_numerical (denom (xx)));
integer_log10_numerical (x) :=
if x >= 10
then (for i from 0 do
if x >= 10 then x:x/10 else return(i))
elseif x < 1
then (for i from 0 do
if x < 1 then x:x*10 else return(-i))
else 0;
是否有像 Excel
中的 round()
那样对数字(甚至十进制数)进行四舍五入的函数?
例子
将 1,45 舍入到一位小数:1,5
将 2,45 舍入到一位小数:2,5
有一个 similar question 但他们使用不同的算法。
四舍五入的问题实际上非常微妙,但我认为这里有一个简单的方法可以提供可行的结果。我在这里定义了一个新函数 myround
,它具有 Excel =ROUND
所描述的行为。 [1]
(%i4) myround (x, n) := round(x*10^n)/10.0^n;
n
'round(x 10 )
(%o4) myround(x, n) := -------------
n
10.0
(%i5) myround (2.15, 1);
(%o5) 2.2
(%i6) myround (2.149, 1);
(%o6) 2.1
(%i7) myround (-1.475, 2);
(%o7) - 1.48
(%i8) myround (21.5, -1);
(%o8) 20.0
(%i9) myround (626.3, -3);
(%o9) 1000.0
(%i10) myround (1.98, -1);
(%o10) 0.0
(%i11) myround (-50.55, -2);
(%o11) - 100.0
[1] https://support.microsoft.com/en-us/office/round-function-c018c5d8-40fb-4053-90b1-b3e7f61a213c
好的,这是在 Maxima 中重新实现 Excel =ROUND 函数的尝试。一些笔记。 (1) 在应用用户舍入之前,值四舍五入到 15 位有效数字。这是为了解决因小数不准确表示为浮点数而导致的问题。 (2) 我已经将 excel_round
和 integer_log10
实现为所谓的简化函数。这意味着直到参数是可以评估的东西(在这种情况下,当参数是数字时)才会执行计算。 (3) 我没有检查 Excel =ROUND 对负数的作用——它是向上舍入 5(即在这种情况下朝零)还是远离零?我不知道。
我已将此解决方案作为小包 excel_round.mac
发布在 Github 上。请参阅:https://github.com/maxima-project-on-github/maxima-packages 并导航至 robert-dodier/excel_round
。为了完整起见,我也在这里粘贴了代码。
这里有几个例子。
(%i1) excel_round (1.15, 1);
(%o1) 1.2
(%i2) excel_round (1.25, 1);
(%o2) 1.3
(%i3) excel_round (12.455, 2);
(%o3) 12.46
(%i4) excel_round (x, 2);
(%o4) excel_round(x, 2)
(%i5) ev (%, x = 9.865);
(%o5) 9.87
这是代码。这是excel_round.mac
.
/* excel_round -- round to specified number of decimal places,
* rounding termminal 5 upwards, as in MS Excel, apparently.
* Inspired by:
*
* copyright 2020 by Robert Dodier
* I release this work under terms of the GNU General Public License.
*/
matchdeclare (xx, numberp);
matchdeclare (nn, integerp);
tellsimpafter (excel_round (xx, nn), excel_round_numerical (xx, nn));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v))));
tellsimpafter (excel_round (xx, nn), excel_round_numerical (ev (xx, numer), nn));
excel_round_numerical (x, n) :=
block ([r, r1, r2, l],
/* rationalize returns exact rational equivalent of float */
r: rationalize (x),
/* First round to 15 significant decimal places.
* This is a heuristic to recover what a user "meant"
* to type in, since many decimal numbers are not
* exactly representable as floats.
*/
l: integer_log10 (abs (r)),
r1: round (r*10^(15 - l)),
/* Now begin rounding to n places. */
r2: r1/10^((15 - l) - n),
/* If terminal digit is 5, then r2 is integer + 1/2.
* If that's the case, round upwards and rescale,
* otherwise, terminal digit is something other than 5,
* round to nearest integer and rescale.
*/
if equal (r2 - floor(r2), 1/2)
then ceiling(r2)/10.0^n
else round(r2)/10.0^n);
matchdeclare (xx, lambda ([e], numberp(e) and e > 0));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (xx));
matchdeclare (xx, lambda ([e], block ([v: ev (e, numer)], numberp(v) and v > 0)));
tellsimpafter (integer_log10 (xx), integer_log10_numerical (ev (xx, numer)));
matchdeclare (xx, lambda ([e], not atom(e) and op(e) = "/" and numberp (denom (e)) and pow10p (denom (e))));
pow10p (e) := integerp(e) and e > 1 and (e = 10 or pow10p (e/10));
tellsimpafter (integer_log10 (xx), integer_log10 (num (xx)) - integer_log10_numerical (denom (xx)));
integer_log10_numerical (x) :=
if x >= 10
then (for i from 0 do
if x >= 10 then x:x/10 else return(i))
elseif x < 1
then (for i from 0 do
if x < 1 then x:x*10 else return(-i))
else 0;