2016-04-10 3 views
2

Язык: ExcelОперации над переменными с первенствует

Здравствуйте & спасибо за чтение моего поста.

Я пытаюсь создать формулу ... умножить ячейки (или в этом случае буквы) на основе переменных. Переменные состоят в том, делится ли он на (1000 + 250x) и, согласно ответу, умножьте его на соответствующее письмо.

Визуальное представление:

A  B  C 
    1% 2% 3% 
    250 500 1000 


1 1,000 
2 1,250 
3 1,500 
4 1,750 
5 2,000 

Например, так как # 1 делится на 1000, я бы умножить на 3% Второй экземпляр, так как # 2 делится на 250 и 1000, я бы умножать 250 на 1% и 1000 на 3%, а затем добавить их вместе.

Моя текущая попытка:

=IF(MOD(A2,F14)<=1,A2*F15,"") 

A2 = начальное количество F14 =, что А2 разделяется на
F15 = процент

Этот вид работ, но он не позволяет мне чтобы найти наилучшее возможное решение.

Большое спасибо за вашу помощь в моей дилемме.

+0

Mr Sparr ow Пожалуйста, улучшите свое сообщение, отредактировав – Prasad

+0

, что вы имеете в виду как «наилучшее возможное решение»? – user3598756

+0

Что я подразумеваю под * наилучшим возможным решением * @ user3598756 ... Например, возьмите номер 3, например. Было бы нецелесообразно взять 500 (из 1500) всего и разделить на 2, затем умножить их на 1%, или, другими словами, взять (((250 * 1%) * 2) + (1000 * 3 %)), INSTEAD, было бы намного лучше ... ((500 * 2%) + (1000 * 3%)) – Sparrow

ответ

0

Я не могу придумать какое-либо хорошее решение по формулам Excel, потому что результат, который вы хотите, слишком сложный: как вы отметили свой вопрос, вам нужен цикл, независимо от того, какие формулы не могут сделать для вас. Я боюсь ,
Но, как вы добавили VBA как один из тегов, я предполагаю VBA решение будет работать для вас, так вот сценарий я написал:

Option Explicit 'variables MUST BE declared, otherwise error. very handy rule 
Option Base 0 'won't be needed this time, but in general, this rule is also a great ally
'(it says: arrays' 1st item will always be the "0th" one)
Dim divLARGE, divMED, divSMALL 'you can use variable types in Excel Dim percLARGE, percMED, percSMALL 'but sadly, not in VBScript which I have ATM

'test input values and their results, won't be needed in your Excel Dim testA, testB, testC, testD, testE, testF 'so add types if you like Dim resA, resB, resC, resD, resE, resF '(should make execution a little faster)

'Init our variables declared above. in VBScript you can't do this at declaration,
'i.e. can't say "Dim whatever As Boolean = true" which would be the right way to do this Call Initialize()

'Call the "main routine" to execute code
Call Main()

'you can add access modifiers here. "private" would be the best
'i.e. "private Sub Main()" Sub Main() resA = CalcMaster(testA, divLARGE) resB = CalcMaster(testB, divLARGE) resC = CalcMaster(testC, divLARGE) resD = CalcMaster(testD, divLARGE) resE = CalcMaster(testE, divLARGE) resF = CalcMaster(testF, divLARGE) MsgBox (CStr(testA) + " --> " + CStr(resA) + vbCrLf + _ CStr(testB) + " --> " + CStr(resB) + vbCrLf + _ CStr(testC) + " --> " + CStr(resC) + vbCrLf + _ CStr(testD) + " --> " + CStr(resD) + vbCrLf + _ CStr(testE) + " --> " + CStr(resE) + vbCrLf + _ CStr(testF) + " --> " + CStr(resF) + vbCrLf) End Sub
Sub Initialize() divLARGE = 1000 'the large number for which we look after remnants divMED = 500 'medium/middle sized number to divide by divSMALL = 250 'the small value percLARGE = 3 'percentage we want if no remnants on LARGE number percMED = 2 'same but for medium/mid size numbers percSMALL = 1 'and the percentage we want for the small remnants
testA=1000 'result should be exactly 30.0 testB=1250 'res == 32.5 testC=1500 'res == 40.0 testD=1750 'res == 42.5 testE=2000 'res == 60.0 testF=-198 'res == #ERROR/INVALID VALUE End Sub
Function CalcMaster(inVar, byDiv) 'A silly function name popped in my mind, sorry :) Dim remnant, percDiv
'sometimes happens, looks cheaper calc.wise to handle like this; if initial input
'can be 0 and that's a problem/error case, handle this scenario some other way If (inVar = 0) Then Exit Function remnant = inVar Mod byDiv 'if you'll implement more options, do a Select...Case instead (faster) If (byDiv = divLARGE) Then percDiv = percLARGE ElseIf (byDiv = divMED) Then percDiv = percMED Else percDiv = percSMALL End If

If (remnant = 0) Then CalcMaster = inVar * (percDiv/100) Exit Function End If 'had remnant; for more than 3 options I would use an array of options 'and call back self with the next array ID If (byDiv = divLARGE) Then CalcMaster = CalcMaster(inVar - remnant, divLARGE) + CalcMaster(remnant, divMED) ElseIf (byDiv = divMED) Then CalcMaster = CalcMaster(inVar - remnant, divMED) + CalcMaster(remnant, divSMALL) Else 'or return 0, or raise error and handle somewhere else, etc 'MsgBox ("wrong input number: " + CStr(inVar)) CalcMaster = -1 End If End Function


Это не идеально, я предполагаю, что там может быть лучшие решения там, но я думайте, что это достаточно хорошо для дела. Надеюсь, вы согласитесь :)
Cheers

+0

Я заметил VBA как возможное решение, хотя мне не хватает опыта в области , Я верю, что смогу забрать его довольно быстро из-за ваших комментариев и моего предыдущего опыта в кодировании. Поскольку вы потратили время на то, чтобы написать код для меня, я отвечу на вашу доброту, потратив время на ее изучение и изучение. Большое спасибо! – Sparrow

+0

@Sparrow Добро пожаловать! Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать. Заранее благодарю вас за то, что пометили свой ответ как решение, если и когда вы смогли собрать его вместе с фактическим Excel и разобрались в проблеме;) –

0

после описания воробья Я понял, что «наилучшее возможное решение» - это то, которое максимизирует «общий приз», полученный путем умножения всех возможных целых делителей (то есть 250, 500, 1000) на их корреспондент «приз» (1%, 2%, 3%)

вот последующее решение

Option Explicit 

Sub main() 
Dim dataRng As Range, cell As Range, percRng As Range, divRng As Range 
Dim i As Long, value As Long, nDivisors As Long 
Dim prize As Double, totalPrize As Double 

Set dataRng = ActiveSheet.Range("B1:B10") '<== here set the range cointaining the numbers to be processed 
Set percRng = ActiveSheet.Range("F15:H15") '<== here set the range of % "prizes": they MUST be in ascending order (from lowest to highest) 
Set divRng = ActiveSheet.Range("F14:H14") '<== here set the range of the possible divisors. this range MUST be of the same size as thre "prizes" range 

For Each cell In dataRng.SpecialCells(xlCellTypeConstants, xlNumbers) 

    value = cell.value 
    nDivisors = 0 
    prize = 0 
    totalPrize = 0 
    Do 
     i = FindMaxDivisor(value, percRng, divRng) 
     If i > 0 Then 
      value = value - divRng(i) ' update value to the remainder 
      prize = percRng(i) * divRng(i) ' get current "prize" 
      totalPrize = totalPrize + prize 'update totalprize 
      nDivisors = nDivisors + 1 'update divisors number 
      cell.Offset(, nDivisors) = divRng(i) 'write divisor in next blank adjacent cell in the number row 
     End If 
    Loop While value > 0 And i >= 0 

    If i >= 0 Then ' the number has been correctly divided by given divisors 
     With cell.Offset(, nDivisors + 1) 
      .value = totalPrize 
      .Font.Color = vbRed 
     End With 
    Else 
     MsgBox "Not possible to break " & cell.value & " into given divisors" 
    End If 

Next cell 

End Sub 


Function FindMaxDivisor(value As Long, percRng As Range, divRng As Range) As Long 
Dim i As Long 

FindMaxDivisor = -1 'default value should not be found any whole divisor 

i = divRng.Columns.Count 
Do While value Mod divRng(i) <> 0 And i > 1 
    i = i - 1 
Loop 

If value Mod divRng(i) = 0 Then FindMaxDivisor = i 

End Function 

каждое число «лучших» делители будут записаны в колонках рядом с номером и в последнем там будет записан «общий приз» в красном

Смежные вопросы