AZJIO
![](http://forum.ru-board.com/board/avatars/private/AZJIO.gif)
Silver Member | Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору embrace909 На тогда ещё быстрей в 5 раз (4 мсек против 20 мсек). Я сначала не понял идеи Daniyar91, подумал он использовал диапазон не только для Y но и для X, поэтому сначала взялся за общий диапазон для Y и X, но в ходе изменения решил сделать цикл используя больший инкремент, чтобы не вычислять холостые ходы, ведь в предыдущем примере как я говорил на один 164.87 приходилось диапазон значений от 100.01 до 100.19. Сами по себе Y и X одинаковы, отсюда их коэфициенты определяют наибольший инкремент. Как только я написал условие, стало понятно что Daniyar91, использовал именно этот метод, ведь у него тоже сравнение коэфициентов. Цитата: Приращения зависят от коэффициентов, нам даже не надо рассчитывать формулу | вычисление инкремента позволило бы в цикле вместо Код: $X = ($Sum - $Y * $ky) / $kx | написать Код: только точность этой величины не позволяет этого сделать. Скорость увеличена за счёт изначальной установки диапазона, чтобы не проверять лишнее в цикле, то есть $iMin и $iMax приобретают меньший диапазон чем указано во входных данных, а причина, что при Х=100, Y будет больше 700, а так как нам большие значения не нужны, то находим такое Х, при котором Y станет не более 700. То есть изначально ставим диапазон начинающийся с валидных значений. То есть и цикл делает меньше шагов и в цикле не требуется проверок выхода за пределы диапазона. Код: #include "Array.au3" ; Входящие данные Local $iMin = 100 Local $iMax = 700 Local $Sum = 753967.76 ; Сумма Local $kx = 4507 ; коэффициент Local $ky = 109 ; коэффициент ; Local $iMin = 1 ; Local $iMax = 10 ; Local $Sum = 26 ; Сумма ; Local $kx = 2 ;коэффициент K1 ; Local $ky = 4 ; коэффициент K2 ; Вычисление $timer = TimerInit() $iMin *= 100 $iMax *= 100 $Sum *= 100 Local $aRes[1][3] = [[0]] ; Local $aRes[511][3] = [[510]] ; вариант изначально с запасом, реального выйгрыша нет ; вычисляем приращение If $kx > $ky Then ; если приращение по Х больше приращения по Y, то вычисляем по большему приращению. $k1 = $kx ; меняем местами коэфициенты $k2 = $ky $c1 = 0 ; меняем местами колонки массива $c2 = 1 Else $k1 = $ky $k2 = $kx $c1 = 1 $c2 = 0 EndIf Local $tmpMin = $iMin ; Если Х (при минимальном значении Y) превышает масксимальный предел, то минимум вычисляем исходя из подстановки максимального значения Х If (($Sum - $iMin * $k1) / $k2) > $iMax Then $iMin = Int(($Sum - $iMax * $k2) / $k1) ; Если Х (при максимальном значении Y) меньше минимального предела, то максимум вычисляем исходя из подстановки минимального значения Х. Используем стемпированную $iMin, так как оригинальная могла нарушится предыдущим выражением. If (($Sum - $iMax * $k1) / $k2) < $tmpMin Then $iMax = Ceiling(($Sum - $tmpMin * $k2) / $k1) $j = 0 For $Yx = $iMin To $iMax $Xy = ($Sum - $Yx * $k1) / $k2 If IsInt($Xy) Then ; проверяем что X целое число $j += 1 If $j > $aRes[0][0] Then ReDim $aRes[$j * 2 + 1][3] $aRes[0][0] = $j * 2 EndIf $aRes[$j][$c1] = $Xy / 100 $aRes[$j][$c2] = $Yx / 100 EndIf Next ReDim $aRes[$j + 1][3] $aRes[0][0] = $j $timer = TimerDiff($timer) ; проверка что результаты согласно формуле дают нужную сумму For $i = 1 To $j $aRes[$i][2] = $aRes[$i][$c1] * $k2 + $aRes[$i][$c2] * $k1 Next _ArrayDisplay($aRes, 'Время ' & Round($timer, 1), -1, 0, '', '|', '№|X|Y|Сумма') | Ещё один вариант, требующий проверки. Ещё в 4 раза быстрей вышеуказанного (0.8 мсек против 4.0 мсек). Отличается тем, что в первом цикле определяет количество шагов сделанных от первого валидного значения до второго валидного значения. Потом выпрыгивает из цикла и начинает новый цикл с шагом например 100. теоритически инкремент величина постоянная, значит следующее целое число будет получено ровно через такое же количество шагов. Сейчас неуверенность в вычислении размера массива. Пока сбоя не давал. Можно сделать с запасом на 2 элемента и потом обрезать в случае если формула окажется не верна. Код: #include "Array.au3" ; Входящие данные Local $iMin = 100 Local $iMax = 700 Local $Sum = 753967.76 ; Сумма Local $kx = 4507 ; коэффициент Local $ky = 109 ; коэффициент ; Local $iMin = 1 ; Local $iMax = 10 ; Local $Sum = 26 ; Сумма ; Local $kx = 2 ;коэффициент K1 ; Local $ky = 4 ; коэффициент K2 ; Local $iMin = 200 ; Local $iMax = 210 ; Local $Sum = 46247.48 ; Сумма ; Local $kx = 208 ; коэффициент К1 ; Local $ky = 17 ; коэффициент К2 ; Вычисление $timer = TimerInit() $iMin *= 100 $iMax *= 100 $Sum *= 100 Local $aRes[1][3] = [[0]] ; Local $aRes[511][3] = [[510]] ; вариант изначально с запасом, реального выйгрыша нет ; вычисляем приращение If $kx > $ky Then ; если приращение по Х больше приращения по Y, то вычисляем по большему приращению. $k1 = $kx ; меняем местами коэфициенты $k2 = $ky $c1 = 0 ; меняем местами колонки массива $c2 = 1 Else $k1 = $ky $k2 = $kx $c1 = 1 $c2 = 0 EndIf Local $tmpMin = $iMin ; Если Х (при минимальном значении Y) превышает масксимальный предел, то минимум вычисляем исходя из подстановки максимального значения Х If (($Sum - $iMin * $k1) / $k2) > $iMax Then $iMin = Int(($Sum - $iMax * $k2) / $k1) ; Если Х (при максимальном значении Y) меньше минимального предела, то максимум вычисляем исходя из подстановки минимального значения Х. Используем стемпированную $iMin, так как оригинальная могла нарушится предыдущим выражением. If (($Sum - $iMax * $k1) / $k2) < $tmpMin Then $iMax = Ceiling(($Sum - $tmpMin * $k2) / $k1) If $iMin > $iMax Then Exit MsgBox(0, 'Сообщение', 'Нет решений') $j = 0 $iStep = 1 For $Yx = $iMin To $iMax ; этот цикл определяет количество шагов, между двумя валидными результатами $Xy = ($Sum - $Yx * $k1) / $k2 If IsInt($Xy) Then ; проверяем что X целое число $j += 1 If $j = 1 Then $tmp = $Yx Else $iStep = $Yx - $tmp ; получаем шаг цикла, при которых целые значения $j -= 1 ExitLoop EndIf If $j > $aRes[0][0] Then ReDim $aRes[$j * 2 + 1][3] $aRes[0][0] = $j * 2 EndIf $aRes[$j][$c1] = $Xy / 100 $aRes[$j][$c2] = $Yx / 100 EndIf Next ; Окончательно определяем размер ; $tmp = Ceiling(($iMax - $Yx + 1) / $s) $tmp = Int(($iMax - $Yx) / $iStep) + 1 ReDim $aRes[$j + $tmp + 1][3] $aRes[0][0] = $j + $tmp For $Yx = $Yx To $iMax Step $iStep ; этот цикл продолжает предыдущий, но используя интервал для получения целых чисел $Xy = ($Sum - $Yx * $k1) / $k2 $j += 1 $aRes[$j][$c1] = $Xy / 100 $aRes[$j][$c2] = $Yx / 100 Next $timer = TimerDiff($timer) ; проверка что результаты согласно формуле дают нужную сумму For $i = 1 To $j $aRes[$i][2] = $aRes[$i][$c1] * $k2 + $aRes[$i][$c2] * $k1 Next _ArrayDisplay($aRes, 'время ' & Round($timer, 1) & ', шаг ' & $iStep, -1, 0, '', '|', '№|X|Y|Сумма') |
| Всего записей: 4579 | Зарегистр. 03-05-2006 | Отправлено: 23:57 18-04-2013 | Исправлено: AZJIO, 01:49 19-04-2013 |
|