Самая большая проблема, которую я вижу, это использование Single
вместо Integer
или Long
. Простые числа являются положительными целыми числами и не рассматриваются в контексте десятичных значений (насколько мне известно). Таким образом, используя одиночные числа и сравнивая их с разделенными целыми числами, вы подвергаете себя неприятным ошибкам маршрутизации в крайних случаях.
Строка If N / D = Int(N / D) Then
использует плохой метод, чтобы определить, являются ли числа простыми. предполагается, что каждый раз, когда вы делите число с плавающей запятой (в данном случае простое) на делитель, если оно имеет десятичный остаток, то целочисленное преобразование этого остатка не будет равным. Тем не менее, я иногда сталкивался с ошибками округления с числами с плавающей запятой при попытке сравнить ответы, и в целом я научился избегать использования преобразования с плавающей запятой в целое как способ сравнения чисел.
Вот некоторый код, который вы можете попробовать вместо этого. Некоторые вещи, которые следует отметить:
- Я изменил типы N и D, чтобы они были длинными, а не одиночными. Это означает, что они не являются числами с плавающей запятой и подвержены возможным ошибкам округления.
- Я также явно преобразовал значение ячейки в длинное. Таким образом, вы знаете в своем коде, что не работаете с типом с плавающей запятой.
- Для сравнения я использовал
Mod
, который возвращает остаток от деления N
на D
. Если остаток равен 0, он возвращает true, и мы знаем, что у нас нет простого числа. (Примечание: остаток часто используется с \
, который возвращает только целочисленное значение результата деления. Mod
и \
обычно используются при точном делении целочисленных типов, что в данном случае очень уместно.
- Наконец, я изменил ваше окно сообщения, чтобы показать фактическое сравниваемое число. Поскольку число в ячейке преобразуется, если пользователь вводит значение с плавающей запятой, ему будет полезно увидеть, во что оно было преобразовано.
Вы, вероятно, также заметите, что этот код работает намного быстрее, чем ваш код, когда вы получаете большие числа в сотни миллионов. '
Sub GetPrime()
Dim N As Long
Dim D As Long
Dim tag As String
N = CLng(Cells(2, 2))
Select Case N
Case Is < 2
MsgBox N & " is not a prime number"
Case Is = 2
MsgBox N & " is a prime number"
Case Is > 2
D = 2
Do
If N Mod D = 0 Then
MsgBox N & " is not a prime number"
tag = "Not Prime"
Exit Do
End If
D = D + 1
Loop While D <= N - 1
If tag <> "Not Prime" Then
MsgBox N & " is a prime number"
End If
End Select
End Sub
ПРИМЕЧАНИЕ. Я изменил имя процедуры на GetPrime
. В вашем коде у вас было:
Private Sub CommandButton1_Click()
В строке выше вы определяете процедуру (также называемую методом или иногда просто называемую подпрограммой). Слово Sub
указывает на то, что вы определяете процедуру в коде, который не возвращает никакого значения. (Иногда вы можете увидеть слово Function
вместо Sub
. Это означает, что процедура возвращает значение, например Private Function ReturnANumber() As Long
.) Процедура (Sub
) — это тело кода, которое будет выполняться при вызове. Также стоит отметить, что макрос Excel хранится в VBA как процедура Sub
.
В вашей строке кода CommandButton1_Click()
— это имя процедуры. Скорее всего, это было создано автоматически путем добавления кнопки в электронную таблицу Excel. Если кнопка привязана к электронной таблице Excel, CommandButton1_Click()
будет выполняться при каждом нажатии кнопки.
В вашем коде Private
указывает область процедуры. Private
обычно означает, что процедура не может быть вызвана вне модуля или класса, в котором она находится. В моем коде я пропустил Private
, потому что вы можете вызвать GetPrime
из другого модуля кода.
Вы упомянули в своих комментариях, что вам пришлось изменить имя моей процедуры с GetPrime()
на CommandButton1_Click()
. Это определенно работает. Однако вы также могли просто вызвать GetPrime
из внутри CommandButton1_Click()
, как показано ниже:
Private Sub CommandButton1_Click()
'The following line of code will execute GetPrime() '
'Since GetPrime does not have parameters and does not return a value, '
'all you need to do is put the name of the procedure without the () '
GetPrime
End Sub
'Below is the entire code for the Sub GetPrime() '
Sub GetPrime()
'The body of the code goes below: '
' ... '
End Sub
Надеюсь, это помогло вам немного объяснить VBA и углубить ваше понимание!
person
Ben McCormack
schedule
19.11.2009
Loop While D <= N - 1
, возможно, наLoop While D <= N/2
для начала. - person Russ Cam   schedule 19.11.2009