Board logo

标题: [讨论]脚本+算法=四舍五入,精确除法运算(申精) [打印本页]

作者: flyinspace     时间: 2007-4-1 23:51    标题: [讨论]脚本+算法=四舍五入,精确除法运算(申精)

突然在帖子里看到了一个关于四舍五入的请教问题!
心里还在笑笑,CMD又不支持四舍五入运算。
但就在转过去看其他的帖子的时候,却灵机一动,想出了如下算法。。
现在把自己的算法写在下面。希望和高手们一起进步。
也希望高手们可以精简自己的代码。
——————————————————————————————————
思想:
取 除法的 余数 ,若余数减去 被除数的二分之一能大于 0 就证明这个数为5入运算。否则为4舍运算。
     加入了对余数的判断,因为余数只能是2n或 2N+1 .若为2n+1,则该数/2后满足4舍5入的条件。若不是,则继续下面的判断
——————————————————————————————————
@echo off & SetLocal EnableDelayedExpansion
set /a 除数=25
set /a 被除数=10
set /a 余数=%除数% %% %被除数%
set /a 参考值=%被除数%/2
set /a 参考值1=%被除数%-%参考值%*2
set /a 进位=%余数%-(%参考值%+%参考值1%)

echo %参考值%,参考值1,%进位%

if %进位% LSS 0 (
           echo %除数% ÷ %被除数% 的结果为 4舍运算!
           set /a 结果=%除数%/%被除数%
           ) else (
           echo %除数% ÷ %被除数% 的结果为 5入运算!
           set /a 结果=%除数%/%被除数%+1
           )
echo 答案为:%结果%
pause
--------------------------------------------------------------------------------------------
在这里我只是抛了一块砖。。却引了一块玉出来。。

大家看看bjsh的代码,一次比一次完善。。

现在基本可以应付任意位数的除法运算,且保证精度了。

大家多给bjsh加分吧:)

[ Last edited by flyinspace on 2007-4-1 at 08:33 PM ]
作者: lxmxn     时间: 2007-4-2 00:06

思路不错,可惜还是不能突破“批处理不能做四舍五入”这个难关。

用27/5试试。

作者: flyinspace     时间: 2007-4-2 00:26
谢谢lxmxn的指出

现在问题已经解决。。

另:拷贝文件时进度条显示进度问题已经解决!

复制文件时,可以看到拷贝的进度了。

只是会产生临时文件。
在硬盘速度过快,拷贝文件过大的情况下有1~3秒的显示差异。

现在考虑修改这个显示问题中。

[ Last edited by flyinspace on 2007-4-1 at 02:04 PM ]
作者: slore     时间: 2007-4-2 00:49
@echo off & SetLocal EnableDelayedExpansion
set /p 除数=
set /p 被除数=
set /a 余数=%除数% %% %被除数%
set /a 参考值=%被除数%/2

if %余数% LSS %参考值% (
           echo %除数% ÷ %被除数% 的结果为 4舍运算!
           set /a 结果=%除数%/%被除数%
           ) else (
           echo %除数% ÷ %被除数% 的结果为 5入运算!
           set /a 结果=%除数%/%被除数%+1
           )
echo 答案为:%结果%
pause


直接判断余数和被除数的1/2不行?为什么要-然后和0比大小?
作者: flyinspace     时间: 2007-4-2 01:02
呵呵,当然行啊。。。。。但现在你复制的这个代码会有问题。
在特殊情况下会出现判断错误的情况。。

回4楼。有道理,是我多做了一下判断。。
准备写个批处理和c程序做除数1-100000 被除数 1-100000的测试。
看代码会不会出现误判的情况。。
作者: bjsh     时间: 2007-4-2 02:27
这是我写的;
精确到你指定的小数点位;四舍五入的;大家帮忙测试下
代码可以再精简的;有时间的话把精简后的发上来;
大家也可以帮忙精简下代码

  Quote:

  1. @echo off &SetLocal EnableDelayedExpansion
  2. set /p x=请输入被除数:
  3. set /p y=请输入除数:
  4. set /p n=请输入欲保留的小数的位数:
  5. set /a count=0
  6. set /a bjsh=10
  7. :loop
  8. if %count% geq %n% goto start
  9. set /a bjsh*=10
  10. set /a count+=1
  11. goto loop
  12. :start
  13. set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
  14. if "%n%"=="0" (set /a last=%x%/%y%) else (
  15. set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
  16. )
  17. if %rest% geq 5 set /a last+=1
  18. if "%n%"=="0" echo 结果为%last% & pause & goto exit
  19. set /a result=%x%/%y%
  20. set result=%result%.
  21. set /a end=%n%-1
  22. set /a bjsh=10
  23. for /l %%i in (1,1,%end%) do (
  24. set /a add=%x%*!bjsh!/%y%-%x%*!bjsh!/10/%y%*10
  25. set result=!result!!add!
  26. set /a bjsh*=10
  27. )
  28. set result=%result%%last%
  29. echo 结果为%result% & pause
  30. :exit
         BJSH发表于:  2007-04-01  13:22

[ Last edited by bjsh on 2007-4-1 at 01:32 PM ]
作者: flyinspace     时间: 2007-4-2 02:44
呵,算法只是提供一种思路而已。。

。不过bjsh真的把这个发挥得不错:)

至于测试嘛。。我想就算了:)
精度不高。不如不测试。

而且既然已经准备写到实用的级别。。
就应该对错误进行判断了。
要不然,这个就没有意义。
作者: bjsh     时间: 2007-4-2 02:48
是的
只能精确到小数点后八位;

再高就会出现随机数字了;

搞到百位以上就会出现莫名其妙的-和数字的组合了;

到这里应该是和系统有关了
作者: bjsh     时间: 2007-4-2 02:52
我写的代码的算法倒是和flyinspace的不同

flyinspace兄的算法是

  Quote:

取 除法的 余数 ,若余数减去 被除数的二分之一能大于 0 就证明这个数为5入运算



  Quote:

我的是:利用把实际结果10^n放大取到欲精确的位的后一位;然后进行判断
{/color]


作者: flyinspace     时间: 2007-4-2 02:53
嗯。那么第一点。需要对输入的位数进行判断!尽量不出现随机数字。。
第二,屏蔽到后面的随机数字。。
第三,出错处理机制。

我想这一点应该不难吧。
作者: bjsh     时间: 2007-4-2 02:57
嗯;
那倒是挺简单的

判断%n% geq 8 提示 精确度不能高于8位; 后面也用不到屏蔽了
至于出错机制;
也只有在前面判断
x y n 是否为数字就可以了;

这个东西我就不加进去了;留给想用的人加吧;反正也就几行代码的问题
作者: flyinspace     时间: 2007-4-2 03:01
呵呵,试一下
100000 / 7

嗯。。你也考虑一下dos进度条实用性的问题吧。。

[ Last edited by flyinspace on 2007-4-1 at 02:05 PM ]
作者: bjsh     时间: 2007-4-2 03:09
用100000/7
只能精确到5位;而且因为第6位不准所以第五位也是不准的;

是不是可以想出一种办法可以是精确度再提高啊
作者: bjsh     时间: 2007-4-2 03:14
用 18/7算了一下;

可以精确到第8位但是第八位也是不准的;

精确到7位是准的;

100000/7 和 18/7 的区别在于位数;

所以10^n放大确实会影响精确度的;

隐约感觉 改进算法会提高精确度;虽然系统本身就存在精确度限制;

但是应该可以发挥到极致
作者: flyinspace     时间: 2007-4-2 03:28
嗯。。看一下你自己的算法。你就明白啦:)

把结果只截取你自己估算的精度出来。

而不只是对输入进行判断。输入只是为了在一定程度上帮助用户不走弯路而已。

核心的还是你自己的脚本代码问题。

你觉得呢??bjsh 兄。
作者: bjsh     时间: 2007-4-2 03:35
稍微简化了下代码

  Quote:

  1. @echo off &SetLocal EnableDelayedExpansion
  2. set /p x=请输入被除数:
  3. set /p y=请输入除数:
  4. set /p n=请输入欲保留的小数的位数:
  5. set /a count=0
  6. set /a bjsh=10
  7. :loop
  8. if %count% geq %n% goto start
  9. set /a bjsh*=10
  10. set /a count+=1
  11. goto loop
  12. :start
  13. set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
  14. if "%n%"=="0" (set /a last=%x%/%y%) else (
  15. set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
  16. )
  17. if %rest% geq 5 set /a last+=1
  18. if "%n%"=="0" echo 结果为:%last% & pause & goto exit
  19. if "%n%"=="1" set /a t=%x%/%y% && echo 结果为:!t!.%last% & pause & goto exit
  20. set /a result=%x%*%bjsh%/100/%y%
  21. set /a end=%n%-1
  22. call echo 结果为:%%result:~0,-%end%%%.%%result:~-%end%%%%%last%% && pause
  23. :exit
         BJSH发表于:  2007-04-01  14:43

flyinspace兄的话我得好好想想

[ Last edited by bjsh on 2007-4-1 at 02:53 PM ]
作者: flyinspace     时间: 2007-4-2 03:49
我们换个算法。。

1,获取 被除数 / 除数 的结果。
2,获取 被除数 / 除数 的余数。
3,被除数 减去 余数 则为实际整除数。
3,若余数为0,则该数被整除。提示整除,后面输出几个0
4,若不为0,则 实际整除数 / 除数为 实际整数位的值(该值一定准确)
5,获取除数的位数。假设为2位。输出的小数点为7位。(两个值不能大于10)
6,使用循环 余数 * 10(10的9次方)
7,6的结果 / 除数 (然后利用4舍5入的算法)(给出提示)输出小数位
8,输出结果 : %整数位%.%小数位%

如此。精度也满足了。你的要求也达到了。

bjsh 觉得如何?
作者: bjsh     时间: 2007-4-2 04:06
flyinspace兄确实给了我提醒;

系统只能精确算出第九位;

也就是说最大精确值是八位;

所以我之前的算法在精确上对于数字较小的绝对没有问题;

比如18/7

但是在大数字上比如100000/7 精度要比前者小;也是和系统最大只能算到第九位有关;

所以在这方面采用flyinspace兄的建议;

先求出余数;把大数字化成小数字;在利用余数去继续除
作者: flyinspace     时间: 2007-4-2 04:10
呵呵,觉得好的话给我加分吧:)

我是不是好赖皮
作者: bjsh     时间: 2007-4-2 04:38
我要修正我前面的话
系统
数字精确度限为 32 位

所以第九位也不是确保算出来的;

例如 set /a p=4000000000/7
C:\>set /a p=4000000000/7
-42138185


所以第八为才是精确算出来的;

所以最后的精确度应为7位
作者: flyinspace     时间: 2007-4-2 04:49
不过是一个long int的问题。。
精度就在这里啊。

set /a p=400000000 % 7
set /a a=400000000 - % p%
set /a 整数部分=(400000000 - %a%) / 7
上面是一定整除的了。
怎么会9位不精确呢。。。。
作者: bjsh     时间: 2007-4-2 04:53
新的代码 精度为7

  Quote:

  1. @echo off &SetLocal EnableDelayedExpansion
  2. set /p x=请输入被除数:
  3. set /p y=请输入除数:
  4. :n
  5. set /p n=请输入欲保留的小数的位数:
  6. if %n% gtr 7 echo 最大精确度为7位请重新输入 && goto n
  7. set /a count=0
  8. set /a bjsh=10
  9. set /a system_result=%x%/%y%
  10. set /a system_rest=%x%%%%y%
  11. set x=%system_rest%
  12. :loop
  13. if %count% geq %n% goto start
  14. set /a bjsh*=10
  15. set /a count+=1
  16. goto loop
  17. :start
  18. set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
  19. if "%n%"=="0" (set /a last=%rest%) else (
  20. set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
  21. )
  22. if "%n%"=="0" if %rest% geq 5 set /a last=%system_result%+1 && echo 结果为:!last! & pause & goto exit
  23. if %rest% geq 5 set /a last+=1
  24. if "%n%"=="1" echo 结果为:%system_result%.%last% & pause & goto exit
  25. set /a result=%x%*%bjsh%/100/%y%
  26. set /a end=%n%-1
  27. call echo 结果为:%%system_result%%.%%result:~-%end%%%%%last%% && pause
  28. :exit
         BJSH发表于:  2007-04-01  15:44


作者: bjsh     时间: 2007-4-2 04:55
flyinspace兄
说的有理啊

通过循环取余;

有可能任意精度啊
作者: bjsh     时间: 2007-4-2 05:46
最终代码了;
精确到任何一位

  Quote:

  1. @echo off
  2. set /p x=请输入被除数:
  3. set /p y=请输入除数:
  4. set /p n=请输入欲保留的小数的位数:
  5. set /a end=%n%-1
  6. set /a count=0
  7. set /a system_result=%x%/%y%
  8. set /a rest=%x%%%%y%
  9. set result=%system_result%.
  10. :loop
  11. set /a rest*=10
  12. set /a last=%rest%/%y%
  13. set /a count+=1
  14. if %count% geq %n% set /a rest=%rest%%%%y%*10/%y% && goto jump_loop
  15. set result=%result%%last%
  16. set /a rest=%rest%%%%y%
  17. goto loop
  18. :jump_loop
  19. if %n%==0 if %last% geq 5 set /a result+=1 && echo 结果为:!result!&& goto exit
  20. if %rest% geq 5 set /a last+=1
  21. echo %result%%last% & pause
         BJSH发表于:  2007-04-01  18:28

[ Last edited by bjsh on 2007-4-1 at 06:40 PM ]
作者: bjsh     时间: 2007-4-2 05:49
这个代码的思想要归功于flyinspace
本想给他加十分;可惜论坛限制只能加两分..

愿看过的各位 替我实现愿望
作者: bjsh     时间: 2007-4-2 07:45
以前的那些突破了下限;
无法计算高于10^9次的下面这个经过修改后;突破了上下限;
可以计算任意位数字;并且可以精确到任意位数;(似乎太大比如1百万位会提示输出行太长)

  Quote:

  1. @echo off & setlocal enabledelayedexpansion
  2. set /p x=请输入被除数:
  3. set /p y=请输入除数:
  4. if %y% gtr 2000000000 echo 除数太大 && goto exit
  5. set /p n=请输入欲保留的小数的位数:
  6. if %x% gtr 2000000000 goto big
  7. :start
  8. set /a count=0
  9. set /a system_result=%x%/%y%
  10. set /a rest=%x%%%%y%
  11. set result=%system_result%.
  12. :loop
  13. set /a rest*=10
  14. set /a last=%rest%/%y%
  15. set /a count+=1
  16. if %count% geq %n% set /a rest=%rest%%%%y%*10/%y% && goto jump_loop
  17. set result=%result%%last%
  18. set /a rest=%rest%%%%y%
  19. goto loop
  20. :jump_loop
  21. if %n%==0 if %last% geq 5 set /a result+=1 && echo 结果为:!result!&& goto exit
  22. if %rest% geq 5 set /a last+=1
  23. echo 结果为:%result%%last% && goto exit
  24. :big
  25. set /a l=0
  26. set result=
  27. :big_loop
  28. set p=%x:~0,1%
  29. set /a m=%l%*10+%p%
  30. set /a s=%m%/%y%
  31. set result=%result%%s%
  32. if "%result%"=="0" set result=
  33. set /a l=%m%%%%y%
  34. set x=%x:~1%
  35. if not defined x goto big_end
  36. goto big_loop
  37. :big_end
  38. set result=%result%.
  39. set /a count=0
  40. set rest=%l%
  41. goto loop
  42. :exit
  43. pause
         BJSH发表于:  2007-04-01  18:56

[ Last edited by bjsh on 2007-11-22 at 10:30 PM ]
作者: bjsh     时间: 2007-4-2 08:01
无法解决除数大于10^9的问题

[ Last edited by bjsh on 2007-4-1 at 08:53 PM ]
作者: flyinspace     时间: 2007-4-2 09:26


  Quote:
Originally posted by bjsh at 2007-4-1 07:01 PM:
无法解决被除数大于10^9的问题

被除数 / 除数 = 结果中。

被除数是可以大于10的9次方的。。
但除数不可以。。

set 被除数=9999999999999999999999999999999
假设这个9有20位。。当然长度可以任意。。

使用 set new=%被除数:~0,9%取9位数出来。。

当然在应用级别的时候。。我们会用for循环解决连续值的问题。。

这里只说明一种情况。。其他的情况你自己搞定啊:)

首先判断 new 是否大于 除数
是--》大于则开始做取余运算。。。

假设除数是111111110。

然后按照上面的方法获得精确的值后。。

获取余数的位数。。

此例子为一位。。。值为9。。

然后在后面利用 set 补上8位。。

如此,循环。。。

把20位的数字全部取完。。
则整数部分的代码搞定了。。
小数部分你自己也会搞啦。。
作者: bjsh     时间: 2007-4-2 09:49
我上面写错了;

是没法解决 除数大于 10^9 的问题;

至于被除数我最后一个代码用的思想和 flyinspace是一样的;

那段代码 对于被除数任意位都可以的

[ Last edited by bjsh on 2007-4-1 at 08:51 PM ]
作者: nanhui112     时间: 2008-1-28 16:28
;)特大数 我采取循环截取取数   但还是有问题  如123456789123456
先取前九位计算 后面再补0 把结果相加计算 有涉及到特大数相加的问题
并且结果也不是很正确 涉及到小数问题 一放大 就有很大数字差距了
看来  cmd  不适合计算  只能做到这个份拉~~~
----前面的都是高手 学习拉 加倍努力拉:)

[ Last edited by nanhui112 on 2008-1-28 at 04:43 PM ]
作者: lovelymorning     时间: 2009-8-8 03:44
回26楼

我用下面数字测试了您这代码,出错了

被除数  94677408

除数  704465856

正确结果为 0.134396……

但用您这代码,算出来的却是

结果为:0.1-201-20

另一组数字

被除数 94987952

除数  704465856

正确结果 0.134836……

您这代码,算出来的却是 结果为:0.1-20020


这两个,保留的小数为 6 位。。。

用了其它的代码,也是这样的结果。。。不知是这两个数搞特殊呢,还是算法有bug呢?
作者: chishingchan     时间: 2009-11-28 18:03
正想找这方面的软件.可惜的不支持纯DOS
作者: echoair     时间: 2010-5-30 23:32
厉害啊,谢谢分享…