Вычислить статическое случайное число (вычислить его один раз) в Excel

Я ищу способ вычислить случайное число один раз в Excel. Таким образом, он вычисляется при первом вызове, но потом он не меняется.

Так, например, если бы у меня было что-то подобное в B1 RANDONCE(A1), то в первый раз, когда я поместил значение в A1, он вычислил бы случайное значение, но тогда оно больше не изменилось бы. Или, по крайней мере, до тех пор, пока я снова не поменяю A1.

Я хотел бы сделать это, не копируя вручную B1, чтобы преобразовать его из формулы в значение, как описано здесь. Использование макросов - это нормально.


person studgeek    schedule 04.11.2011    source источник
comment
Как долго стоимость должна оставаться неизменной? Через сеанс, после сохранения и т. Д.?   -  person Tim Williams    schedule 04.11.2011
comment
Если вас устраивает значение, которое на самом деле не является «случайным», а просто непрозрачным, вы можете использовать что-нибудь, связанное с stackoverflow.com/questions/3498356/md5-hash-function-in-excel для вычисления хеш-функции значения в A1.   -  person AakashM    schedule 04.11.2011
comment
Похоже, вы хотите мероприятия. Я добавил ответ ниже. Обратите внимание, что вы можете присвоить B1 его значение (из формулы) за один шаг в VBA, поэтому вам не нужно делать это так, как они опубликовали в той ссылке, которую вы добавили.   -  person aevanko    schedule 05.11.2011


Ответы (6)


Вам нужен UDF с памятью, чтобы он знал, изменилась ли ячейка

Этот UDF будет возвращать новое случайное значение при изменении упомянутого вызова, в противном случае возвращает последнее случайное значение (т.е. без изменений). Также возвращает пустое значение, если исходная ячейка пуста (может или не может быть тем, что вам нужно?)

Примечание. Проблема заключается в том, что значения Static теряются при закрытии листа, поэтому значение будет изменяться каждый раз при открытии листа.

Function randonce(r As Range)
    Static trigger As Variant
    Static v As Double
    If r <> trigger Then
        v = Rnd
        trigger = r
    End If
    If Len(r) <> 0 Then
        randonce = v
    Else
        randonce = vbNullString
    End If
End Function
person chris neilsen    schedule 04.11.2011
comment
Спасибо за этот ответ, @ChrisNeilsen! Чтобы стать универсальным решением, потребовалось всего несколько небольших настроек. Первая строка: Function RandOnce(Low As Long, High As Long, r As Range) As Long Измените v = Rnd на v = Int(Rnd * (High + 1 - Low)) + Low и добавьте 'Randomize' после объявлений, чтобы убедиться, что ГСЧ получает перезагрузить. - person TesseractE; 27.12.2014

Думаю, у меня есть более простой способ сделать это. Заполните свою электронную таблицу, затем примените функцию = СЛУЧМЕЖДУ для этого столбца чисел. Затем сделайте это:

  1. Скопируйте результаты из этого столбца.
  2. Выделите столбец и выберите «Специальная вставка» и выберите «Значения».

Теперь у вас есть последние созданные значения, и они статичны.

person Adam    schedule 15.11.2013

Вы можете создать UDF (определяемую пользователем функцию):

Public Function Rand_once(ByVal r As Range)
    Rand_once = Rnd
End Function

В ячейку, в которой вы хотите получить результат, вы можете поместить:

=Rand_once(A1)

Значение изменится (фактически, будет пересчитано) только при изменении исходного значения (также известного как A1).

person JMax    schedule 04.11.2011
comment
-1 Это изменит значение, если лист имеет полный пересчет (например, нажмите ctrl-alt-F9) - person chris neilsen; 04.11.2011
comment
OP не уточнил, и я думаю, что этого будет достаточно, учитывая предоставленную им информацию. - person JMax; 05.11.2011
comment
Я не согласен. Я думаю, но тогда это не изменится снова, исключает изменение при полном пересчете. - person chris neilsen; 05.11.2011

Вы также можете использовать циклические ссылки для создания полностью управляемого формулой «переключателя», позволяющего пользователю вычислять набор случайных чисел, а затем отключать дальнейшие пересчеты. Отключить предупреждения о циклических ссылках, а затем поместите эту формулу в ячейку B3:

=IF($B$1="YES",RAND(),B3)

Если ячейка B1 содержит «ДА», B3 будет генерировать новое случайное число при каждом пересчете электронной таблицы; если B1 содержит любое другое значение, текущее значение B3 будет сохранено.

person Scott Forbes    schedule 11.03.2014

Это, очевидно, не будет лучшим решением, если вам нужно отслеживать много ячеек, но если вам нужно отслеживать изменения просто A1, вы можете использовать событие для выполнения своей функции в B1, а затем в конец, присвойте ему присвоенное значение. Я считаю это самым простым решением, и оно работает так, как вам нужно.

Пример:

Private Sub Worksheet_Change(ByVal Target As Range)

If Target.Address = "$A$1" Then
    With Cells(1, 2)
        .Value = "=rand()" 'or whatever
        .Value = .Value
    End With
End If

End Sub
person aevanko    schedule 05.11.2011
comment
Если вам нужно отслеживать много ячеек, вы можете использовать Intersect, чтобы сделать его более читаемым. Тем не менее, я считаю это решение довольно отличным, поскольку оно, очевидно, не изменит значение (всякий раз, когда Full Recalc или около того, см. Обсуждение с Крисом под моим ответом), пока A1 не изменится (поэтому я думаю, что это требует +1 :)) - person JMax; 05.11.2011

Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Public Function MySessionRand(Optional seedMod As Single = 0) As Single
    Dim seed As Single
    seed = (-1 * GetCurrentProcessId) - seedMod
    MySessionRand = Rnd(seed)
End Function

Это решение использует текущее значение PID Excel в качестве начального числа. Умножение на -1 приводит к тому, что каждый раз при вызове rnd () используется одно и то же число, поэтому, пока сеанс активен, PID не изменится. 'seedMod' предназначен для помощи функции повторного заполнения, если это необходимо, и может использоваться, например, с. СТРОКА () или КОЛОНКА ().

Public Function MySessionRand2(Optional seed As Single = 0, Optional min As Double = 0, Optional max As Long = 1) As Double
    ' if called with default values will produce either 0 or 1
    If min >= max Then max = min + 1
    MySessionRand2 = Int((max - min + 1) * MySessionRand(seed) + min)
End Function

И дополнительная функция для случайного диапазона.

person Machine    schedule 08.02.2021