ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 872|回复: 1

[原创] 分数类

[复制链接]

TA的精华主题

TA的得分主题

发表于 2019-12-3 02:02 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 weixing1531 于 2019-12-4 18:32 编辑

最近在学习类模块
手痒就试着编写了一个分数类
初学
不足之处请多多指教

以下为源代码:
类模块代码
  1. '类模块 (名称) 改为 Rational
  2. 'Creat 构造方法
  3. 'RalAddRal RalAddNum 加法 函数
  4. 'RalSubRal RalSubNum 减法 函数
  5. 'RalTimesRal RalTimesNum 乘法 函数
  6. 'RalDivRal RalDivNum 除法 函数
  7. 'RalPowerInt 乘方 函数
  8. 'Negative 相反数 函数
  9. 'Real2Ral 浮点数转换为分数 子程序
  10. 'Ral2Real 分数转换为双精度浮点数 函数
  11. 'Output 打印 子程序
  12. Option Explicit
  13. Private num_&   '分子 &代表长整数 4字节 下同
  14. Private denom_& '分母

  15. Private Sub Class_Initialize() '指定分数初始值
  16.   num_ = 0
  17.   denom_ = 1
  18. End Sub
  19. '个人认为写操作用子程序比用属性更安全
  20. Public Sub Setnum(x&) '写分子 子程序
  21.   num_ = x
  22. End Sub

  23. Public Sub Setdenom(y&) '写分母 子程序
  24.   denom_ = y
  25. End Sub
  26. '属性只可读
  27. Public Property Get num&() '读分子 属性
  28.   num = num_
  29. End Property

  30. Public Property Get denom&() '读分母 属性
  31.   denom = denom_
  32. End Property

  33. Public Sub Creat(x&, Optional y&) '构造方法
  34.   num_ = x
  35.   
  36.   If IsMissing(y) Then '不传入分母
  37.     denom_ = 1 '分母默认为1
  38.   Else '传入分母
  39.     If (y <= 0) Then
  40.       MsgBox "分母不能为非正数!", vbExclamation
  41.       End ' 提前结束程序
  42.     End If

  43.     denom_ = y
  44.   End If
  45.   
  46.   'Call Reduse(Me) '这里暂不进行约分
  47. End Sub

  48. Private Function Gcv&(a&, b&) '返回最大公约数
  49.   Dim big&, small&, temp&

  50.   big = Application.Max(a, b) 'VBA居然没有内置max min函数
  51.   small = Application.Min(a, b)

  52.   Do While (small > 1) '辗转除法
  53.     temp = big Mod small
  54.     If temp = 0 Then Exit Do
  55.     big = small
  56.     small = temp
  57.   Loop

  58.   Gcv = small
  59. End Function
  60.   
  61. Private Sub Reduse(a As Rational) '约分 调用后改变了a
  62.     Dim b&, sign&

  63.     If a.denom = 0 Then
  64.       MsgBox "分母不能为0!", vbExclamation
  65.       End ' 提前结束程序
  66.     End If

  67.     If a.num = 0 Then   '分子为0
  68.       Call a.Setdenom(1)  '分母强制为1
  69.       Exit Sub '提前返回
  70.     End If

  71.     'If a.num * a.denom > 0 Then '同号 积超大可能会溢出
  72.     If (a.num > 0 And a.denom > 0) Or (a.num < 0 And a.denom < 0) Then '同号
  73.       sign = 1
  74.     Else '异号
  75.       sign = -1
  76.     End If

  77.     Call a.Setnum(Abs(a.num))   '正分子
  78.     Call a.Setdenom(Abs(a.denom)) '正分母
  79.     b = Gcv(a.num, a.denom) '最大公约数

  80.     Call a.Setnum(a.num / b * sign)   '分子带符号
  81.     Call a.Setdenom(a.denom / b)  '保证分母始终为正
  82. End Sub
  83.   
  84. Public Function RalAddRal(b As Rational) As Rational '加法
  85.   Set RalAddRal = New Rational '对象实例
  86.   
  87.   Call RalAddRal.Setnum(num_ * b.denom + b.num * denom_)
  88.   Call RalAddRal.Setdenom(denom_ * b.denom)   '通分
  89.   Call Reduse(RalAddRal)  '约分
  90. End Function

  91. Public Function RalAddNum(b As Variant) As Rational '加法
  92.   '利用VarType实现简单重载 b可以为整数、浮点数
  93.   Select Case VarType(b)  'VarType返回变体的具体类型
  94.   Case vbInteger, vbLong, vbByte 'Integer Long Byte整数
  95.     Set RalAddNum = New Rational '对象实例
  96.     Call RalAddNum.Setnum(num_ + denom_ * b)
  97.     Call RalAddNum.Setdenom(denom_)
  98.     Call Reduse(RalAddNum)  '约分
  99.   Case vbDouble, vbSingle '双、单精度浮点数
  100.     Dim temp As New Rational
  101.     Call temp.Real2Ral(CDbl(b)) 'CDbl将变体类型转换为双精度浮点数
  102.     '转换为分数相加 单精度转换为分数可能误差较大
  103.     Set RalAddNum = Me.RalAddRal(temp) 'Me为对象实例
  104.     '加法已经约分过了
  105.     Set temp = Nothing
  106.   Case Else
  107.     MsgBox "类型错误!", vbExclamation
  108.     End ' 提前结束程序
  109.   End Select
  110. End Function

  111. Public Function RalSubRal(b As Rational) As Rational '减法
  112.   Set RalSubRal = New Rational '对象实例
  113.   
  114.   Call RalSubRal.Setnum(num_ * b.denom - b.num * denom_)
  115.   Call RalSubRal.Setdenom(denom_ * b.denom)   '通分
  116.   Call Reduse(RalSubRal)  '约分
  117. End Function

  118. Public Function RalSubNum(b As Variant) As Rational '减法
  119.   'a-b=a+(-b)
  120.   Set RalSubNum = Me.RalAddNum(-b) 'Me为对象实例
  121. End Function

  122. Public Function RalTimesRal(b As Rational) As Rational '乘法
  123.   Set RalTimesRal = New Rational '对象实例
  124.   
  125.   Call RalTimesRal.Setnum(num_ * b.num)
  126.   Call RalTimesRal.Setdenom(denom_ * b.denom)
  127.   Call Reduse(RalTimesRal)  '约分
  128. End Function

  129. Public Function RalTimesNum(b As Variant) As Rational '乘法
  130.   '利用VarType实现简单重载 b可以为整数、浮点数
  131.   Select Case VarType(b)  'VarType返回变体的具体类型
  132.   Case vbInteger, vbLong, vbByte 'Integer Long Byte整数
  133.     Set RalTimesNum = New Rational '对象实例
  134.     Call RalTimesNum.Setnum(num_ * b)
  135.     Call RalTimesNum.Setdenom(denom_)
  136.     Call Reduse(RalTimesNum)  '约分
  137.   Case vbDouble, vbSingle '双、单精度浮点数
  138.     Dim temp As New Rational
  139.     Call temp.Real2Ral(CDbl(b)) 'CDbl将变体类型转换为双精度浮点数
  140.     '转换为分数相乘 单精度转换为分数可能误差较大
  141.     Set RalTimesNum = Me.RalTimesRal(temp) 'Me为对象实例
  142.     '乘法已经约分过了
  143.     Set temp = Nothing
  144.   Case Else
  145.     MsgBox "类型错误!", vbExclamation
  146.     End ' 提前结束程序
  147.   End Select
  148. End Function

  149. Public Function RalDivRal(b As Rational) As Rational '除法
  150.   Set RalDivRal = New Rational '对象实例
  151.   
  152.   Call RalDivRal.Setnum(num_ * b.denom)
  153.   Call RalDivRal.Setdenom(denom_ * b.num)
  154.   Call Reduse(RalDivRal)  '约分
  155. End Function

  156. Public Function RalDivNum(b As Variant) As Rational '除法
  157.   '利用VarType实现简单重载 b可以为整数、浮点数
  158.   Select Case VarType(b)  'VarType返回变体的具体类型
  159.   Case vbInteger, vbLong, vbByte 'Integer Long Byte整数
  160.     Set RalDivNum = New Rational '对象实例
  161.     Call RalDivNum.Setnum(num_)
  162.     Call RalDivNum.Setdenom(denom_ * b)
  163.     Call Reduse(RalDivNum)  '约分
  164.   Case vbDouble, vbSingle '双、单精度浮点数
  165.     Dim temp As New Rational
  166.     Call temp.Real2Ral(CDbl(b)) 'CDbl将变体类型转换为双精度浮点数
  167.     '转换为分数相除 单精度转换为分数可能误差较大
  168.     Set RalDivNum = Me.RalDivRal(temp) 'Me为对象实例
  169.     '乘法已经约分过了
  170.     Set temp = Nothing
  171.   Case Else
  172.     MsgBox "类型错误!", vbExclamation
  173.     End ' 提前结束程序
  174.   End Select
  175. End Function

  176. Public Function RalPowerInt(b&) As Rational '乘方
  177.   Set RalPowerInt = New Rational '对象实例
  178.   
  179.   If b > 0 Then
  180.     Call RalPowerInt.Setnum(num_ ^ b)
  181.     Call RalPowerInt.Setdenom(denom_ ^ b)
  182.   ElseIf b < 0 Then
  183.     Call RalPowerInt.Setnum(denom_ ^ (-b))
  184.     Call RalPowerInt.Setdenom(num_ ^ (-b))
  185.   Else 'b==0  0^1=1
  186.     Call RalPowerInt.Setnum(1)
  187.     Call RalPowerInt.Setdenom(1)
  188.     Exit Function '提前返回
  189.   End If
  190.   
  191.   Call Reduse(RalPowerInt)  '约分
  192. End Function
  193. '浮点数转换为分数
  194. '应该会有更好的算法 这里用的是暴力转换
  195. Public Sub Real2Ral(a As Double)
  196.   Const N As Long = 100000
  197.   Dim i As Long
  198.    
  199.   i = Fix(a)  '取整 去尾
  200.   denom_ = N  '假定分母超大
  201.   num_ = CLng((a - i) * N)  '小数部分扩大N倍后四舍五入
  202.   Call Reduse(Me) '约分后一定真分数
  203.   num_ = num_ + i * denom_ '真分数叠加整数
  204. End Sub
  205. '分数转换为双精度浮点数
  206. Public Function Ral2Real() As Double
  207.   If denom_ = 0 Then
  208.     MsgBox "分母为0!", vbExclamation
  209.     End ' 提前结束程序
  210.   End If
  211.   
  212.   Ral2Real = num_ / denom_
  213. End Function

  214. Public Function Negative() As Rational  '相反数 取负
  215.   Set Negative = New Rational '对象实例
  216.   Call Negative.Setdenom(denom_)
  217.   Call Negative.Setnum(-num_)
  218. End Function

  219. Public Sub Output() '打印
  220.   Debug.Print num_ & "/" & denom_ '立即窗口显示结果
  221. End Sub
复制代码


标准模块代码
  1. Option Explicit

  2. Sub main()
  3.   Dim a As New Rational '对象实例
  4.   Dim b As New Rational '对象实例
  5.   Dim c As Rational 'c是引用 下同

  6.   Call a.Creat(1, 2)
  7.   Call a.Output
  8.   Call b.Creat(1, 3)
  9.   Call b.Output
  10.   Set c = a.RalAddRal(b) '分数加分数
  11.   Call c.Output '打印
  12.   Set c = a.RalAddNum(2.25) '分数加数字
  13.   Call c.Output '打印
  14.   Set c = a.RalSubRal(b) '分数减分数
  15.   Call c.Output
  16.   Set c = a.RalSubNum(2.25) '分数减数字
  17.   Call c.Output '打印
  18.   Set c = a.RalTimesRal(b) '分数乘分数
  19.   Call c.Output
  20.   Set c = a.RalTimesNum(2.25) '分数乘数字
  21.   Call c.Output '打印
  22.   Set c = a.RalDivRal(b) '分数除以分数
  23.   Call c.Output
  24.   Set c = a.RalDivNum(2.25) '分数除以数字
  25.   Call c.Output '打印
  26.   Set c = a.RalPowerInt(3) '乘方
  27.   Call c.Output
  28.   Set c = a.Negative() '取相反数
  29.   Call c.Output
  30.   Call c.Real2Ral(-1.125) '浮点数转换为分数
  31.   Call c.Output
  32. End Sub
复制代码


分数类型(试验).zip (26.04 KB, 下载次数: 7)

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-12-5 17:52 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
以下是分数类型正式版1.0  
加入了比较逻辑函数

分数类型(正式版).zip

33.97 KB, 下载次数: 5

Excel文件

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-26 10:26 , Processed in 0.036421 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表