Numeri Random partendo da un valore di riferimento ed avendo una media finale prestbilita

Anonimo
2017-12-23T06:20:02+00:00

Buongiorno a tutti,

tempo fa il buon Norman mi creò un codice (per me impossibile) che mi serviva ad estrapolare valori random partendo da un numero preimpostato.

Adesso avrei bisogno di aggiungere, nello stesso codice, il valore medio prestabilito.

Con il seguente codice, se lancio la macro più volte e controllo il valore medio di tutti i dati, gli stessi variano sempre. Di poco ma variano. Vorrei poter sfruttare una cella ove inserire esattamente il valore medio che desidero e poi sfruttare lo stesso codice che faccia esattamente le stesse cose ma la media finale risulti uguale a quella impostata nella cella. Ovviamente se ometto il valore medio dalla cella il codice si dovrà comportare esattamente come sta facendo adesso.

Ringrazio ancora Norman per questo codice che a tutt'oggi mi aiuta tantissimo per compilare i dati di fine anno.

Allo stesso modo approfitto per farvi i miei migliori auguri di buone feste.

Di seguito il codice di Norman:ùSaluti

Giuseppe

=========>>

Option Explicit

'--------->>

Public Sub Tester3()

    Dim WB As Workbook

    Dim SH As Worksheet

    Dim rngPrimaData, rngUltimaData

    Dim rngPrimoOrario As Range, rngUltimoOrario As Range

    Dim rigaStart As Long, rigaFine As Long

    Dim riga2Start As Long, riga2Fine As Long

    Dim rngMediaValle As Range, rngScartoMediaValle As Range

    Dim Rng As Range, Rng2 As Range, Rng3 As Range

    Dim rArea As Range

    Dim LRow As Long

    Dim iMin As Long, iMax As Long

    Dim Criterio1 As Double, Criterio2 As Double

    Dim bManutenzione As Boolean

    Const cellaPrimaData As String = "C4"                                '<<=== Modifica

    Const cellaUltimaData As String = "D4"                              '<<=== Modifica

    Const cellaPrimoOrario As String = "C6"                             '<<=== Modifica

    Const cellaUltimoOrario As String = "D6"                           '<<=== Modifica

    Const cellaMediaValle As String = "B3"                               '<<=== Modifica

    Const cellaScartoMediaValle As String = "B5"                    '<<=== Modifica

    Const iPrimaRiga As Long = 14                                            '<<=== Modifica

    bManutenzione = True

    Set WB = ThisWorkbook

    Set SH = WB.ActiveSheet

    With SH

        Set rngPrimaData = .Range(cellaPrimaData)

        Set rngUltimaData = .Range(cellaUltimaData)

        Set rngPrimoOrario = .Range(cellaPrimoOrario)

        Set rngUltimoOrario = .Range(cellaUltimoOrario)

        Set rngMediaValle = .Range(cellaMediaValle)

        Set rngScartoMediaValle = .Range(cellaScartoMediaValle)

        LRow = LastRow(SH, .Columns("A:A"))

        With .Columns(1)

            If IsEmpty(rngPrimaData.Value) _

               Or IsEmpty(rngUltimaData.Value) Then

                bManutenzione = False

                Set Rng = .Cells(iPrimaRiga).Offset(0, 3). _

                          Resize(LRow - iPrimaRiga + 1)

            End If

            If bManutenzione Then

                Criterio1 = CDbl(rngPrimaData.Value + rngPrimoOrario)

                Criterio2 = CDbl(rngUltimaData + rngUltimoOrario)

                rigaStart = SH.Columns(1).Find( _

                            What:=CDate(Criterio1), _

                            After:=.Cells(iPrimaRiga - 1), _

                            LookIn:=xlFormulas, _

                            LookAt:=xlPart, _

                            SearchOrder:=xlByRows, _

                            SearchDirection:=xlNext, _

                            MatchCase:=False).Row

                rigaFine = SH.Columns(1).Find( _

                           What:=CDate(Criterio1), _

                           After:=.Cells(iPrimaRiga - 1), _

                           LookIn:=xlFormulas, _

                           LookAt:=xlPart, _

                           SearchOrder:=xlByRows, _

                           SearchDirection:=xlPrevious, _

                           MatchCase:=False).Row

                riga2Start = SH.Columns(1).Find( _

                             What:=CDate(Criterio2), _

                             After:=.Cells(iPrimaRiga - 1), _

                             LookIn:=xlFormulas, _

                             LookAt:=xlPart, _

                             SearchOrder:=xlByRows, _

                             SearchDirection:=xlNext, _

                             MatchCase:=False).Row

                riga2Fine = SH.Columns(1).Find( _

                            What:=CDate(Criterio2), _

                            After:=.Cells(iPrimaRiga - 1), _

                            LookIn:=xlFormulas, _

                            LookAt:=xlPart, _

                            SearchOrder:=xlByRows, _

                            SearchDirection:=xlPrevious, _

                            MatchCase:=False).Row

                Set Rng2 = .Cells(iPrimaRiga).Resize(rigaStart - iPrimaRiga)

                Set Rng3 = .Cells(riga2Fine + 1).Resize(LRow - riga2Fine)

                '            End With

                Set Rng = Union(Rng2, Rng3).Offset(, 3)

            End If

            iMin = rngMediaValle.Value - rngScartoMediaValle.Value

            iMax = rngMediaValle.Value + rngScartoMediaValle.Value

        End With

    End With

    On Error GoTo XIT

    Application.ScreenUpdating = False

    With Rng

        .NumberFormat = "0.00"

        .Formula = "=RANDBETWEEN(" & iMin & "," & iMax & ")*1.01"

        For Each rArea In Rng.Areas

            With rArea

                .Select

                .Value = .Value

                .Interior.Color = vbYellow   '\ Solo per facilitare le prove!

            End With

        Next rArea

    End With

XIT:

    Application.ScreenUpdating = True

End Sub

'--------->>

Public Function LastRow(SH As Worksheet, _

                        Optional Rng As Range, _

                        Optional minRow As Long = 1)

    If Rng Is Nothing Then

        Set Rng = SH.Cells

    End If

    On Error Resume Next

    LastRow = Rng.Find(What:="*", _

                       After:=Rng.Cells(1), _

                       LookAt:=xlWhole, _

                       LookIn:=xlFormulas, _

                       SearchOrder:=xlByRows, _

                       SearchDirection:=xlPrevious, _

                       MatchCase:=False).Row

    On Error GoTo 0

    If LastRow < minRow Then

        LastRow = minRow

    End If

End Function

'<<=========

Microsoft 365 e Office | Excel | Per la casa | Windows

Domanda bloccata. Questa domanda è stata eseguita dalla community del supporto tecnico Microsoft. È possibile votare se è utile, ma non è possibile aggiungere commenti o risposte o seguire la domanda.

0 commenti Nessun commento
Risposta accettata dall'autore della domanda
Anonimo
2017-12-27T11:52:53+00:00

Ciao Giuseppe,

credo, a meno di errori di valutazione, che o ci sia bisogno di un maggior numero di cicli o addirittura la media richiesta, dati i valori di partenza iMin e iMax (che sono degli interi a cui viene applicata una maggiorazione dell'1%) non possa essere trovata se non probabilità veramente molto basse.

Ti faccio un esempio per far capire il problema.

Nell'intervallo A1:A1000 ho inserito la seguente funzione: =CASUALE.TRA(1;500)

in D1 ho inserito: =MEDIA(A1:A1000)

in D2 ho inserito: 248,545 (che rappresenta un valore medio possibile in quanto restituito dalla suddetta funzione in D1.

in D3 semplicemente =D1=D2 per avere VERO quando i due valori, quello calcolato in D1 e quello inserito manualmente in D2 sono uguali

Poi con una procedura simile a quella della tua routine (anche se molto semplificata) ho provato a lanciare il ciclo dopo un ricalcolo che cambiasse i valori in A1:A1000 e la media in D1.

Per avere nuovamente valori che mi restituissero 248,545 in diversi tentativi ci sono voluti ad es.

 12978        Vero

 572          Vero

 28167        Vero

 3513         Vero

 24258        Vero

 14010        Vero

perché in D3 venisse nuovamente restituto Vero.

Come puoi vedere a volte ci sono voluti più di 10.000 ricalcoli prima che la media dei numeri casuali restituiti corrispondesse a quella inserita manualmente.

Per assurdo la media potrebbe anche essere 1 o 500 (i due valori estremi).

Ma la probabilità che si verifichi che tutte e 1.000 le formule restituiscano solo 1 o solo 500 sono molto basse.

I miei ricordi di statistica sono molto flebili ma 1/500 (2 possibilità su 1000) è la probabiltà che la funzione restitusica il valore 1. Questa probabilità poi si deve ripetere per 1.000 volte contemporaneamente (quindi sarebbe 2 su 1.000.000? boh ... dovrei andare a rispolverare i libri di statistica :)).

La risposta è stata utile?

1 persona ha trovato utile questa risposta.
0 commenti Nessun commento

6 risposte aggiuntive

Ordina per: Più utili
  1. Anonimo
    2017-12-27T18:24:25+00:00

    Mi fa piacere che tu abbia trovato una soluzione.

    Ma una domanda. Che differenza ci sarebbe tra la "media a valle" e la tua media "preimpostata"?

    Perchè vedo che parti da quel valore, a cui aggiungi e sottrai un differenziale, per avere i valori minimo e massimo, anche se come valori interi, a cui poi aggiungi un 1% al valore restituito dalla formula "CAUSAL.TRA".

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2017-12-27T17:53:31+00:00

    Grazie Casanmaner,

    Ho fatto un accrocchio che almeno funziona.

    Praticamente ho fatto la differenza tra la media ottenuta e quella voluta ed aggiunto la differenza a tutti i valori in colonna.

    Alla fine mi trovo la media preimpostata.

    Grazie mille del tuo prezioso aiuto.

    Buon Anno a tutti.

    La risposta è stata utile?

    0 commenti Nessun commento
  3. Anonimo
    2017-12-27T09:21:26+00:00

    Buongiorno Casanmaner e tutti,

    ho provato il codice modificato ed ovviamente funziona.

    L'unico problema è che non mi da effettivamente la media voluta ma molto prossima.

    A me servirebbe esattamente il valore medio inserito in E4. Ho anche provato ad aumentare i cicli a 1000 ma non riesco ad ottenere il risultato voluto.

    Ci potrebbe essere un altro modo per risolvere il problema?

    Anticipatamente ringrazio

    Saluti

    Giuseppe

    La risposta è stata utile?

    0 commenti Nessun commento
  4. Anonimo
    2017-12-23T08:29:16+00:00

    Ciao Giuseppe,

    non ho avuto modo di testarla perché non ho a disposizione i tuoi dati ma se vuoi prova, in una copia del tuo file, la macro così modificata (dove in grassetto metto in rilievo le modifiche specifiche per "gestire" la media finale prestabilita:

    Public Sub Tester3ModificataPerMediaFinalePrestabilita()

        Dim WB As Workbook

        Dim SH As Worksheet

        Dim rngPrimaData, rngUltimaData

        Dim rngPrimoOrario As Range, rngUltimoOrario As Range

        Dim rigaStart As Long, rigaFine As Long

        Dim riga2Start As Long, riga2Fine As Long

        Dim rngMediaValle As Range, rngScartoMediaValle As Range

        Dim Rng As Range, Rng2 As Range, Rng3 As Range

        Dim rArea As Range

        Dim LRow As Long

        Dim iMin As Long, iMax As Long

        Dim Criterio1 As Double, Criterio2 As Double

        Dim bManutenzione As Boolean

        Dim ContaCicli As Long

        Const cellaPrimaData As String = "C4"                                '<<=== Modifica

        Const cellaUltimaData As String = "D4"                              '<<=== Modifica

        Const cellaPrimoOrario As String = "C6"                             '<<=== Modifica

        Const cellaUltimoOrario As String = "D6"                           '<<=== Modifica

        Const cellaMediaValle As String = "B3"                               '<<=== Modifica

        Const cellaScartoMediaValle As String = "B5"                    '<<=== Modifica

        Const iPrimaRiga As Long = 14                                            '<<=== Modifica

    '< dichiarazioni variabili e costanti per gestire media finale prestabilita

    Dim rngMediaFinalePrestabilita As Range

    Dim iMediaPrestabilita As Double

    Const cellaMediaFinalePrestabilita As String = "E4" '<<=== da personalizzare

    Const iMaxNumeroCicli As Long = 100

    'dichiarazioni variabili e costanti per gestire media finale prestabilita />

        bManutenzione = True

        Set WB = ThisWorkbook

        Set SH = WB.ActiveSheet

        With SH

            Set rngPrimaData = .Range(cellaPrimaData)

            Set rngUltimaData = .Range(cellaUltimaData)

            Set rngPrimoOrario = .Range(cellaPrimoOrario)

            Set rngUltimoOrario = .Range(cellaUltimoOrario)

            Set rngMediaValle = .Range(cellaMediaValle)

            Set rngScartoMediaValle = .Range(cellaScartoMediaValle)

            LRow = LastRow(SH, .Columns("A:A"))

            With .Columns(1)

                If IsEmpty(rngPrimaData.Value) _

                   Or IsEmpty(rngUltimaData.Value) Then

                    bManutenzione = False

                    Set Rng = .Cells(iPrimaRiga).Offset(0, 3). _

                              Resize(LRow - iPrimaRiga + 1)

                End If

                If bManutenzione Then

                    Criterio1 = CDbl(rngPrimaData.Value + rngPrimoOrario)

                    Criterio2 = CDbl(rngUltimaData + rngUltimoOrario)

                    rigaStart = SH.Columns(1).Find( _

                                What:=CDate(Criterio1), _

                                After:=.Cells(iPrimaRiga - 1), _

                                LookIn:=xlFormulas, _

                                LookAt:=xlPart, _

                                SearchOrder:=xlByRows, _

                                SearchDirection:=xlNext, _

                                MatchCase:=False).Row

                    rigaFine = SH.Columns(1).Find( _

                               What:=CDate(Criterio1), _

                               After:=.Cells(iPrimaRiga - 1), _

                               LookIn:=xlFormulas, _

                               LookAt:=xlPart, _

                               SearchOrder:=xlByRows, _

                               SearchDirection:=xlPrevious, _

                               MatchCase:=False).Row

                    riga2Start = SH.Columns(1).Find( _

                                 What:=CDate(Criterio2), _

                                 After:=.Cells(iPrimaRiga - 1), _

                                 LookIn:=xlFormulas, _

                                 LookAt:=xlPart, _

                                 SearchOrder:=xlByRows, _

                                 SearchDirection:=xlNext, _

                                 MatchCase:=False).Row

                    riga2Fine = SH.Columns(1).Find( _

                                What:=CDate(Criterio2), _

                                After:=.Cells(iPrimaRiga - 1), _

                                LookIn:=xlFormulas, _

                                LookAt:=xlPart, _

                                SearchOrder:=xlByRows, _

                                SearchDirection:=xlPrevious, _

                                MatchCase:=False).Row

                    Set Rng2 = .Cells(iPrimaRiga).Resize(rigaStart - iPrimaRiga)

                    Set Rng3 = .Cells(riga2Fine + 1).Resize(LRow - riga2Fine)

                    '            End With

                    Set Rng = Union(Rng2, Rng3).Offset(, 3)

                End If

                iMin = rngMediaValle.Value - rngScartoMediaValle.Value

                iMax = rngMediaValle.Value + rngScartoMediaValle.Value

            End With

        End With

        On Error GoTo XIT

     With Application

    .ScreenUpdating = False

    .Calculation = xlCalculationManual 'calcolo in manuale prima di inserire le formule RANDBETWEEN

    End With

    '< settaggi per media finale prestabilita

    Set rngMediaFinalePrestabilita = SH.Range(cellaMediaFinalePrestabilita)

    iMediaPrestabilita = rngMediaFinalePrestabilita.Value

    ' settaggi per media finale prestabilita />

        With Rng

            .NumberFormat = "0.00"

            .Formula = "=RANDBETWEEN(" & iMin & "," & iMax & ")*1.01"

    '< gestione media finale prestabilita

    If iMediaPrestabilita <> 0 And _

    iMin < iMediaPrestabilita And _

    iMax > iMediaPrestabilita Then

    While Application.Average(.Value) <> iMediaPrestabilita And _

    ContaCicli < iMaxNumeroCicli

    .Calculate

    ContaCicli = ContaCicli + 1

    Wend

    Else

    Rng.Calculate

    End If

    ' gestione media finale prestabilita />

            For Each rArea In Rng.Areas

                With rArea

                    .Select

                    .Value = .Value

                    .Interior.Color = vbYellow   '\ Solo per facilitare le prove!

                End With

            Next rArea

        End With

    XIT:

    With Application

    .Calculation = xlCalculationAutomatic 'reimposto il calcolo in automatico

    .ScreenUpdating = True

    End With

    End Sub

    In pratica le modifiche impostano il calcolo in manuale prima di inserire le formule CAUSALE.TRA, e se il valore in una cella dedicata all'inserimento della media prestabilita (io ho indicato nella costante E4 ma ovviamente da personalizzare in base alla tua esigenza) è diversa da zero ed è un valore compreso tra iMin e iMax esegue un ciclo di ricalcolo del range dove sono presenti le formule.

    Il ciclo continua fino a che non c'è corrispondenza tra la media dei valori ricalcolati nel range e la media prestabilita.

    Viene però anche fissato un limite di cicli (anche questo da personalizzare) per uscire dal ciclo nel caso in cui la media dei valori presenti nel range non venisse trovata.

    Questo per evitare che il ciclo continui all'infinito se la media dei valori presenti nel range non dovesse mai corrispondere alla media preimpostata.

    Se vuoi prova la procedura in attesa di una risposta del buon Norman.

    ciao

    La risposta è stata utile?

    0 commenti Nessun commento