数制转换函数

dfwxj 2006-04-10 03:30:08
没事干,写了两个数制转换函数,以十进制数为基础,与二进制、八进制、十六进制相互转换,没有考虑容错,请大家提供优化,若有价值,再添加容错代码,增加小数

func dectoboh
para ndec,n0
local chex,i,ts
on erro retu ''
chex=''
i=0
ts='0123456789ABCDEF'
ndec=abs(ndec)
do while ndec>=n0
i=mod(ndec,n0)
ndec=int(ndec/n0)
chex=subs(ts,i+1,1)+chex
endd
chex=subs(ts,ndec+1,1)+chex
on erro
retu chex

功能:将十进制数转换为二、八、十六进制
语法:DecToBOH(十进制数,进制)
说明:十进制数为整数数值型,进制为数值型,返回字符型,出错返回空串,测试版,仅支持整数

***********************************
func bohtodec
para chex,n0
local ndec,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,ta,tb,tc,td,te,tf,i,j
on erro retu 0
ndec=0
t0=0
t1=1
t2=2
t3=3
t4=4
t5=5
t6=6
t7=7
t8=8
t9=9
ta=10
tb=11
tc=12
td=13
te=14
tf=15
chex=allt(chex)
j=len(chex)
for i=1 to j
tt=subs(chex,i,1)
ndec=ndec+t&tt.*n0^(j-i)
endf
on erro
retu ndec

功能:将二、八、十六进制数转换为十进制
语法:BOHToDec(二八十六进制数,进制)
说明:二八十六进制数为字符型,进制为数值型,返回数值型,出错返回0,测试版,仅支持整数

**********************

由于没有容错代码,会出现很多奇怪的结果哦,例如:dectoboh(20,17),返回结果为“13”
...全文
1033 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
jingxijun 2006-06-09
  • 打赏
  • 举报
回复
学习
十豆三 2006-05-10
  • 打赏
  • 举报
回复
不用2年,超了清风,就已经远远超过我了。
sdsthgt 2006-05-01
  • 打赏
  • 举报
回复
努力学习,勤学苦练,
1年内超过清风,2年赶十三豆
dfwxj 2006-05-01
  • 打赏
  • 举报
回复
有志气
淡蓝冰 2006-04-22
  • 打赏
  • 举报
回复
好!值得收藏!
十豆三 2006-04-21
  • 打赏
  • 举报
回复
有道理,再改进。
dfwxj 2006-04-21
  • 打赏
  • 举报
回复
酒喝多了,慢慢看,小数与整数处理是相反,整数是“除某取余”,小数是“乘某取整”
ljydomybest 2006-04-21
  • 打赏
  • 举报
回复
鼓励!
十豆三 2006-04-21
  • 打赏
  • 举报
回复
我重新整理了一下,加入了处理小数部分,请清风、唠叨及各位朋友看看,有没有需要改正或优化的地方:

* 本函数能够处理2进制到36进制之间任意正数(包括带小数的数值)的相互转换。

* 以下为常用的进制使用范例
lc2='1111011.101'
lc8='173.5'
lc10='123.625'
lc16='7B.A'
CLEAR
?Base_Convert(lc8,8,2) &&8进制转成2进制
?Base_Convert(lc10,10,2) &&10进制转成2进制
?Base_Convert(lc16,16,2) &&16进制转成2进制
?''
?Base_Convert(lc2,2,8) &&2进制转成8进制
?Base_Convert(lc10,10,8) &&10进制转成8进制
?Base_Convert(lc16,16,8) &&16进制转成8进制
?''
?Base_Convert(lc2,2,10) &&2进制转成10进制
?Base_Convert(lc8,8,10) &&8进制转成10进制
?Base_Convert(lc16,16,10) &&16进制转成10进制
?''
?Base_Convert(lc2,2,16) &&2进制转成16进制
?Base_Convert(lc8,8,16) &&8进制转成16进制
?Base_Convert(lc10,10,16) &&10进制转成16进制

FUNCTION Base_Convert(cNumber,nFromBase,nToBase)
IF PARAMETERS()#3
MESSAGEBOX('参数个数不对!',16,'错误')
RETURN ''
ENDIF
IF VARTYPE(cNumber)#'C' OR VARTYPE(nFromBase)#'N' OR VARTYPE(nToBase)#'N'OR !BETWEEN(nFromBase,2,36) OR !BETWEEN(nToBase,2,36)
MESSAGEBOX('参数类型不对!',16,'错误')
RETURN ''
ENDIF
PRIVATE ALL
lnDecBak=SET('DECIMALS')
SET DECIMALS TO 18
dict="0123456789ABCDEFGHIJKLMNOPQISTUVWXYZ"
cNumber=UPPER(ALLTRIM(TRANSFORM(cNumber)))
nDecimalsWZ=AT('.',cNumber) &&判断是否带小数
IF nDecimalsWZ>0
cNumber2=SUBSTR(cNumber,nDecimalsWZ+1)
cNumber=LEFT(cNumber,nDecimalsWZ-1)
ELSE
cNumber2=''
ENDIF
dec=0
n0=LEN(cNumber)
FOR I=1 TO n0
ch=SUBSTR(cNumber,I,1)
N=AT(ch,dict)
IF !BETWEEN(N,1,nFromBase)
RETURN ''
ENDIF
dec=dec+(N-1)*nFromBase^(n0-I)
ENDFOR
dec2=0
n02=LEN(cNumber2)
FOR I=1 TO n02
ch2=SUBSTR(cNumber2,I,1)
N2=AT(ch2,dict)
IF !BETWEEN(N2,1,nFromBase)
RETURN ''
ENDIF
dec2=dec2+(N2-1)/nFromBase^I
ENDFOR
IF nToBase=10
SET DECIMALS TO (lnDecBak)
IF dec2=0
RETURN TRANSFORM(dec)
ELSE
RETURN numTOstr(dec+dec2)
ENDIF
ENDIF
Convert=''
DO WHILE dec>=nToBase
N=MOD(dec,nToBase)
dec=INT(dec/nToBase)
Convert=SUBSTR(dict,N+1,1)+Convert
ENDDO
Convert=SUBSTR(dict,dec+1,1)+Convert
Convert2=''
DO WHILE dec2>0
N2=INT(dec2*nToBase)
dec2=dec2*nToBase-N2
Convert2=Convert2+SUBSTR(dict,N2+1,1)
ENDDO
SET DECIMALS TO (lnDecBak)
IF LEN(Convert2)>0
RETURN Convert+'.'+Convert2
ELSE
RETURN Convert
ENDIF
ENDFUNC

FUNCTION numTOstr &&将带小数的数值转换为字符型数值,并去掉后面补位的0
LPARAMETERS lnNum
PRIVATE ALL
lnDecBak=SET('DECIMALS')
SET DECIMALS TO 18
DO CASE
CASE VERSION(5)<700 &&VFP6及以下
lcNum=TRANSFORM(lnNum)
CASE VERSION(5)>=700 AND VERSION(5)<900 &&VFP7、8
lcNum=TRANSFORM(lnNum)
IF AT('.',lcNum)>0
lnNumLen=LEN(lcNum)
FOR I=lnNumLen TO 1 STEP -1
IF !SUBSTR(lcNum,I,1)=='0'
EXIT
ENDIF
ENDFOR
lcNum=LEFT(lCNum,I)
ENDIF
CASE VERSION(5)>=900 &&VFP9及以上
lcNum=ALLTRIM(TRANSFORM(lnNum),'0')
ENDCASE
SET DECIMALS TO (lnDecBak)
RETURN lcNum
ENDFUNC
dfwxj 2006-04-20
  • 打赏
  • 举报
回复
还有一个问题

?Base_Convert(cNumber,nFromBase,)

这时在“IF !BETWEEN(frombase,2,36) OR !BETWEEN(tobase,2,36)”提示“操作符/操作数类型不匹配”
dfwxj 2006-04-20
  • 打赏
  • 举报
回复
这样一改更加严密,不过原来的代码输入的类型不受影响的
十豆三 2006-04-20
  • 打赏
  • 举报
回复
FUNCTION Base_Convert(cNumber,nFromBase,nToBase)
IF PARAMETERS()#3 OR VARTYPE(cNumber)#'C' OR VARTYPE(nFromBase)#'N' OR ;
VARTYPE(nToBase)#'N'OR !BETWEEN(nFromBase,2,36) OR !BETWEEN(nToBase,2,36)
MESSAGEBOX('参数个数或类型不对!',16,'错误')
RETURN ''
ENDIF
PRIVATE ALL
dict="0123456789ABCDEFGHIJKLMNOPQISTUVWXYZ"
cNumber=UPPER(ALLTRIM(TRANSFORM(cNumber)))
dec=0
n0=LEN(cNumber)
FOR I=1 TO n0
ch=SUBSTR(cNumber,i,1)
N=AT(ch, dict)
IF !BETWEEN(N,1,nFromBase)
RETURN ''
ENDIF
dec=dec+(N-1)*nFromBase^(n0-i)
NEXT
IF nToBase=10
RETURN ALLTRIM(STR(dec))
ENDIF
Convert=''
DO WHILE dec>=nToBase
N=MOD(dec,nToBase)
dec=INT(dec/nToBase)
Convert=SUBSTR(dict,N+1,1)+Convert
ENDDO
convert=SUBSTR(dict,dec+1,1)+convert
RETURN Convert
ENDFUNC
dfwxj 2006-04-20
  • 打赏
  • 举报
回复
代码已经修改,吸取了xuzuning(唠叨)用AT函数得到字符所表示的数值的做法,加了参数检验,
返回值为字符型,当输入值中存在与源进制不配套的字符时返回空值
N=AT(ch, dict)
IF !BETWEEN(N,1,frombase)
RETURN ''
ENDIF
转换为十进制时用“dec=dec+(N-1)*frombase^(N0-i)”,容易读懂

请测试

FUNCTION BASE(NUMBER, frombase, tobase)
IF PARAMETERS()#3 OR VARTYPE(frombase)#'N' OR VARTYPE(frombase)#'N'
MESSAGEBOX('参数类型出错!',16,'错误')
RETURN ''
ENDIF
IF !BETWEEN(frombase,2,36) OR !BETWEEN(tobase,2,36)
RETURN ''
ENDIF
PRIVATE ALL
dict="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
NUMBER=UPPER(ALLTRIM(TRANSFORM(NUMBER)))
dec=0
n0=LEN(NUMBER)
FOR i=1 TO n0
ch=SUBSTR(NUMBER,i,1)
N=AT(ch, dict)
IF !BETWEEN(N,1,frombase)
RETURN ''
ENDIF
dec=dec+(N-1)*frombase^(N0-i)
NEXT
IF tobase=10
RETURN ALLTRIM(STR(dec))
ENDIF
convert=''
DO WHILE dec>=tobase
N=MOD(dec,tobase)
dec=INT(dec/tobase)
convert=SUBSTR(dict,N+1,1)+convert
ENDDO
convert=SUBSTR(dict,dec+1,1)+convert
RETURN convert
ENDFUNC
dfwxj 2006-04-20
  • 打赏
  • 举报
回复
xuzuning(唠叨)

循环外面的这一句有问题,
convert = SUBSTR(dict, n+1, 1) + convert

除以进制最后一个数是不够除的,是最后第二次的商数,而不是余数,应改成:
convert = SUBSTR(dict, dec+1, 1) + convert
十豆三 2006-04-18
  • 打赏
  • 举报
回复
10进制转为8进制不对
8进制转为10进制对

10进制转为2进制不对
2进制转为10进制对
dfwxj 2006-04-18
  • 打赏
  • 举报
回复
最高只能限制到36进制,超过后失去意义
dfwxj 2006-04-18
  • 打赏
  • 举报
回复
xuzuning(唠叨)的思路不错,稍加改进,目前容错不好
xuzuning 2006-04-18
  • 打赏
  • 举报
回复
首先,dectoboh(20,17),返回结果为“13”是正确的
17进制的13由“1”十进制17和“3”十进制3组成,转换为十进制就是20

这是我的代码:

* 语法: string base_convert(string number, int frombase, int tobase)
* 传回值: 字符串
* 说明
* 本函数将数字符字串 number 从以 frombase 进位转换到以 tobase 进位。
* 本函数能够处理的由以二进位到以三十六进位之间的进位方式。
* 在十进位之前都是以数字表示,而在超过十进位之后就用英文字母表示。
* 例如十六进位个位数依序为 123456789abcdef,10 的顺序是第十七个,这时才进一位。
* 而三十六进位 a 是第十个、b 为第十一个、z 为第三十六个、10 是第三十七个,这时才进位。
*
* 使用范例
* 本例将十六进位字串转成二进位字串
* hexadecimal = 'ff0c'
* binary = base_convert(hexadecimal, 16, 2);
* ? "十六进位字串'"+hexadecimal+"'转成二进位为'"+binary"'。"
*

? base_convert('ff0c', 16, 2)

FUNCTION base_convert(number, frombase, tobase)
PRIVATE ALL
dict = "0123456789ABCDEFGHIJKLMNOPQISTUVWXYZ"
number = UPPER(ALLTRIM(TRANSFORM(number)))
dec = 0
FOR i=1 TO LEN(number)
ch = SUBSTR(number, i, 1)
n = AT(ch, dict)
IF n > 0
dec = dec*frombase + (n - 1)
ENDIF
NEXT
IF tobase = 10
RETURN dec
ENDIF
convert = ''
DO WHILE dec >= tobase
n = MOD(dec, tobase)
dec = INT(dec/tobase)
convert = SUBSTR(dict, n+1, 1) + convert
ENDDO
convert = SUBSTR(dict, n+1, 1) + convert
RETURN convert
ENDFUNC
xuzuning 2006-04-18
  • 打赏
  • 举报
回复

DO WHILE dec >= tobase
n = MOD(dec, tobase)
dec = INT(dec/tobase)
convert = SUBSTR(dict, n+1, 1) + convert
ENDDO
convert = SUBSTR(dict, n+1, 1) + convert

换成
DO WHILE dec > 0
n = MOD(dec, tobase)
dec = INT(dec/tobase)
convert = SUBSTR(dict, n+1, 1) + convert
ENDDO
这样就不错了

我的代码中有
IF n > 0
dec = dec*frombase + (n - 1)
ENDIF
即不是字符集中的字符不参与数制转换,当然你可以做其他判错操作

另外
n = AT(ch, dict)
应改做
n = AT(ch, LEFT(dict, frombase))
这样当输入值中存在不与源进制配套的字符时也能检查出来
dfwxj 2006-04-18
  • 打赏
  • 举报
回复
看来还得以10进制为基础进行转换

因为10进制与其他进制(例如2进制)转换是“除二取余”,而2进制转换为10进制是用各位上的数乘以2的N次幂,转换方式不一样,看来还得分两条路走。

可以采取xuzuning(唠叨)的思路,语法格式用:base_convert(字符串,源进制,目标进制)

先将字符串从源进制转换到10进制,再将10进制转换为目标进制,最高支持36进制,只支持正整数转换,先对字符串进行合法性检验,出错输出空串
加载更多回复(16)

2,723

社区成员

发帖
与我相关
我的任务
社区描述
VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧