производительность — PHP Loops — Runtime — Очень продвинутая тонкая настройка — Рассчитайте коэффициенты смешивания

Я хочу рассчитать коэффициенты смешивания, но у меня есть проблемы во время выполнения,
Кажется, 7 компонентов с точностью до 4% являются пределом в PHP …
Поэтому я стараюсь найти способ избежать лишних циклов, чтобы быстрее вычислять.

У меня есть ингредиенты и лимит (здесь 6). Я хочу найти все комбинации
ниже 6. В шаге звука (здесь не показан) я просто заказываю эти
Хиты после цены. Я хотел бы найти самую дешевую комбинацию с
ингредиент_x ниже 6.

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

<?php

$beginn = microtime(true);
$loops = 0;
$hits = 0;

$m =  array();

// 1. TEST
$component[0]['ingredient_x'] = 6.95;
$component[1]['ingredient_x'] = 65.7;
$component[2]['ingredient_x'] = '';
$component[3]['ingredient_x'] = 2;
$component[4]['ingredient_x'] = '';
$component[5]['ingredient_x'] = '';
$component[6]['ingredient_x'] = '';

/*
Results:

With abort Loops
Loops: 285.188
Hits: 285.077
Seconds: 1,707 sec.

Without:
Loops: 736.281
Hits: 285.077
Seconds: 6,582 sec.
*/

// 2. TEST
$component[0]['ingredient_x'] = 6.95;
$component[1]['ingredient_x'] = 6.7;
$component[2]['ingredient_x'] = '';
$component[3]['ingredient_x'] = 2;
$component[4]['ingredient_x'] = '';
$component[5]['ingredient_x'] = '';
$component[6]['ingredient_x'] = '';

/*
Results:

With abort Loops
Loops: 735.244
Hits: 735.167
Seconds: 4,467 sec.

Without:
Loops: 736.281
Hits: 735.167
Seconds: 3,191 sec.
*/$abort_loops = 1;for ($m[0] = 0; $m[0] <= 100;                                                   $m[0] += 4) {
for ($m[1] = 0; $m[1] <= (100 - $m[0]);                                         $m[1] += 4) {
for ($m[2] = 0; $m[2] <= (100 - $m[0] - $m[1]);                                 $m[2] += 4) {
for ($m[3] = 0; $m[3] <= (100 - $m[0] - $m[1] - $m[2]);                         $m[3] += 4) {
for ($m[4] = 0; $m[4] <= (100 - $m[0] - $m[1] - $m[2] - $m[3]);                 $m[4] += 4) {
for ($m[5] = 0; $m[5] <= (100 - $m[0] - $m[1] - $m[2] - $m[3] - $m[4]);         $m[5] += 4) {
$m[6]  = (100 - $m[0] - $m[1] - $m[2] - $m[3] - $m[4] - $m[5]);

$loops++;

if ($abort_loops) {

$r = 0;
$do_break = 0;

// Checking ingredient_x sum, component by component
for ($i = 0; $i <= 6; $i++) {
$r += ($m[$i] * ($component[$i]['ingredient_x'] / 100));

// If Limit is reached, end all following loops
if ($r > 6) {
$m[$i] = 100;
// Cant break here, because of inner loop ...
$do_break = 1;
}
}
// ... so do it outside
if ($do_break) {
break;
}

$hits++;

} else {

// just sum ingredient_x
$r = ($m[0] * ($component[0]['ingredient_x'] / 100)) +
($m[1] * ($component[1]['ingredient_x'] / 100)) +
($m[2] * ($component[2]['ingredient_x'] / 100)) +
($m[3] * ($component[3]['ingredient_x'] / 100)) +
($m[4] * ($component[4]['ingredient_x'] / 100)) +
($m[5] * ($component[5]['ingredient_x'] / 100)) +
($m[6] * ($component[6]['ingredient_x'] / 100));

if ($r <= 6) {
$hits++;
}
}

}
}
}
}
}
}

print('Loops: ' . number_format($loops, 0, '', '.') . '<br>');
print('Hits: ' . number_format($hits, 0, '', '.') .  '<br>');
print('Seconds: ' . number_format((microtime(true) - $beginn), 3, ',', '') . ' sec.');?>

Но это очень зависит от ингредиентов. Как вы можете видеть в тесте 1
(прерывание цикла в 5 раз быстрее) и Тест 2 (простой способ суммирования быстрее).

Можно ли сделать эти петли быстрее? Лучший код «отменить цикл»?
Есть ли более быстрый способ найти самую дешевую комбинацию?

2

Решение

Один из подходов — использовать простую математику для подведения итогов:

// just sum ingredient_x
$r = (
$m[0] * $component[0]['ingredient_x'] +
$m[1] * $component[1]['ingredient_x'] +
$m[2] * $component[2]['ingredient_x'] +
$m[3] * $component[3]['ingredient_x'] +
$m[4] * $component[4]['ingredient_x'] +
$m[5] * $component[5]['ingredient_x'] +
$m[6] * $component[6]['ingredient_x']
);
;

if ($r <= 600) {
$hits++;
}

Все деления на 100 могут быть полностью сняты, если вы просто увеличите свой лимит в 100 раз.

a0 / 100 + a1 / 100 + a2/100 + ... a6/100

такой же как

(a0 + a1 + a2 + ... + a6) /100

Для этого понадобится только одно деление вместо 7.

Даже этого разделения можно избежать, если вы установите ограничение в 100 *.

Скорость улучшения на моей машине составляет около 10-15%.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]