标题: [讨论]脚本+算法=四舍五入,精确除法运算(申精)
[打印本页]
作者: 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: |
- @echo off &SetLocal EnableDelayedExpansion
- set /p x=请输入被除数:
- set /p y=请输入除数:
- set /p n=请输入欲保留的小数的位数:
- set /a count=0
- set /a bjsh=10
- :loop
- if %count% geq %n% goto start
- set /a bjsh*=10
- set /a count+=1
- goto loop
- :start
- set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
- if "%n%"=="0" (set /a last=%x%/%y%) else (
- set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
- )
- if %rest% geq 5 set /a last+=1
- if "%n%"=="0" echo 结果为%last% & pause & goto exit
- set /a result=%x%/%y%
- set result=%result%.
- set /a end=%n%-1
- set /a bjsh=10
- for /l %%i in (1,1,%end%) do (
- set /a add=%x%*!bjsh!/%y%-%x%*!bjsh!/10/%y%*10
- set result=!result!!add!
- set /a bjsh*=10
- )
- set result=%result%%last%
- echo 结果为%result% & pause
- :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: |
- @echo off &SetLocal EnableDelayedExpansion
- set /p x=请输入被除数:
- set /p y=请输入除数:
- set /p n=请输入欲保留的小数的位数:
- set /a count=0
- set /a bjsh=10
- :loop
- if %count% geq %n% goto start
- set /a bjsh*=10
- set /a count+=1
- goto loop
- :start
- set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
- if "%n%"=="0" (set /a last=%x%/%y%) else (
- set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
- )
- if %rest% geq 5 set /a last+=1
- if "%n%"=="0" echo 结果为:%last% & pause & goto exit
- if "%n%"=="1" set /a t=%x%/%y% && echo 结果为:!t!.%last% & pause & goto exit
- set /a result=%x%*%bjsh%/100/%y%
- set /a end=%n%-1
- call echo 结果为:%%result:~0,-%end%%%.%%result:~-%end%%%%%last%% && pause
- :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: |
- @echo off &SetLocal EnableDelayedExpansion
- set /p x=请输入被除数:
- set /p y=请输入除数:
- :n
- set /p n=请输入欲保留的小数的位数:
- if %n% gtr 7 echo 最大精确度为7位请重新输入 && goto n
- set /a count=0
- set /a bjsh=10
- set /a system_result=%x%/%y%
- set /a system_rest=%x%%%%y%
- set x=%system_rest%
- :loop
- if %count% geq %n% goto start
- set /a bjsh*=10
- set /a count+=1
- goto loop
- :start
- set /a rest=%x%*%bjsh%/%y%-%x%*%bjsh%/10/%y%*10
- if "%n%"=="0" (set /a last=%rest%) else (
- set /a last=%x%*%bjsh%/10/%y%-%x%*%bjsh%/100/%y%*10
- )
- if "%n%"=="0" if %rest% geq 5 set /a last=%system_result%+1 && echo 结果为:!last! & pause & goto exit
- if %rest% geq 5 set /a last+=1
- if "%n%"=="1" echo 结果为:%system_result%.%last% & pause & goto exit
- set /a result=%x%*%bjsh%/100/%y%
- set /a end=%n%-1
- call echo 结果为:%%system_result%%.%%result:~-%end%%%%%last%% && pause
- :exit
BJSH发表于: 2007-04-01 15:44 |
|
作者: bjsh
时间: 2007-4-2 04:55
flyinspace兄
说的有理啊
通过循环取余;
有可能任意精度啊
作者: bjsh
时间: 2007-4-2 05:46
最终代码了;
精确到任何一位
Quote: |
- @echo off
- set /p x=请输入被除数:
- set /p y=请输入除数:
- set /p n=请输入欲保留的小数的位数:
- set /a end=%n%-1
- set /a count=0
- set /a system_result=%x%/%y%
- set /a rest=%x%%%%y%
- set result=%system_result%.
- :loop
- set /a rest*=10
- set /a last=%rest%/%y%
- set /a count+=1
- if %count% geq %n% set /a rest=%rest%%%%y%*10/%y% && goto jump_loop
- set result=%result%%last%
- set /a rest=%rest%%%%y%
- goto loop
- :jump_loop
- if %n%==0 if %last% geq 5 set /a result+=1 && echo 结果为:!result!&& goto exit
- if %rest% geq 5 set /a last+=1
- 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: |
- @echo off & setlocal enabledelayedexpansion
- set /p x=请输入被除数:
- set /p y=请输入除数:
- if %y% gtr 2000000000 echo 除数太大 && goto exit
- set /p n=请输入欲保留的小数的位数:
- if %x% gtr 2000000000 goto big
- :start
- set /a count=0
- set /a system_result=%x%/%y%
- set /a rest=%x%%%%y%
- set result=%system_result%.
- :loop
- set /a rest*=10
- set /a last=%rest%/%y%
- set /a count+=1
- if %count% geq %n% set /a rest=%rest%%%%y%*10/%y% && goto jump_loop
- set result=%result%%last%
- set /a rest=%rest%%%%y%
- goto loop
- :jump_loop
- if %n%==0 if %last% geq 5 set /a result+=1 && echo 结果为:!result!&& goto exit
- if %rest% geq 5 set /a last+=1
- echo 结果为:%result%%last% && goto exit
- :big
- set /a l=0
- set result=
- :big_loop
- set p=%x:~0,1%
- set /a m=%l%*10+%p%
- set /a s=%m%/%y%
- set result=%result%%s%
- if "%result%"=="0" set result=
- set /a l=%m%%%%y%
- set x=%x:~1%
- if not defined x goto big_end
- goto big_loop
- :big_end
- set result=%result%.
- set /a count=0
- set rest=%l%
- goto loop
- :exit
- 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
厉害啊,谢谢分享…