0

I have a measurand like 55.9 mm and I want to divide it in different gauge blocks. Just like: 55.9 mm = 1.4 mm + 1.5 mm + 50 mm + 3 mm

But it can happen that I don't have the 1.4 gauge block. So I need to use something like:

55.9 mm = 1.44 mm + 1.46 mm + 50 mm + 3 mm

As you see i have to substitute the 1.4 and 1.5 gauge blocks.

I am wrinting a PHP-script that calculates which possible gauge blocks I can use, based on the available gauge blocks.

How is it possible to check, wich gauge block with two decimal places replaces a gauge block with one decimal place.

The available blocks are stored in an array.

Here is the complete code:

<?php

function decimalPlaces($number) {
    $str = strval($number);
    $pos = strrpos($number, '.');
    return ($pos===false ? 0 : strlen($str)-$pos-1);
}

function gaugeBlocks($measurement, $em0, $em1, $em2, $em3){
    if($measurement == 0){
    return;
}
$dp = decimalPlaces($measurement);
$gauge = array();

if($dp == 3){
    foreach($em3 as $em){
        $newMeasurement = round($measurement, 3) - $em;
        if(decimalPlaces($measurement - $em) == 2){
            echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
            $gauge[] = $em;
            if($newMeasurement == 0){
                echo "HELL NO 3";
            }else{
                gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
            }
        }
    }
}

if($dp == 2){
    $splitDec = explode(".", round($measurement, 2));
    $zielEM = floatval("1.".$splitDec[1]);

    if($zielEM < 1.50){
        foreach($em2 as $em){
            if($em == $zielEM){
                $newMeasurement = round($measurement, 2)-$em;
                echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                    $gauge[] = $em;
                    if($newMeasurement == 0){
                        echo "HELL NO 2";
                    }else{
                        gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                    }
                }
            }else{
                $lastDigitMeasurement = floatval(substr($measurement, -1));
                $lastDigitEM = floatval(substr($em, -1));
                if($lastDigitEM == $lastDigitMeasurement){
                    $newMeasurement = round($measurement, 2)-$em;
                    echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                    if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                        $gauge[] = $em;
                        if($newMeasurement == 0){
                            echo "HELL NO 2";
                        }else{
                            gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                        }
                    }
                }
            }
        }
    }else{
        $nextEM = $zielEM-0.5;
        foreach($em2 as $em){
            if($em == $nextEM){
                echo "da noch?";
                $newMeasurement = round($measurement, 2)-$em;
                echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                    $gauge[] = $em;
                    if($newMeasurement == 0){
                        echo "HELL NO 2";
                    }else{
                        gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                    }
                }
            }
        }

    }
}

if($dp == 1){
    $splitDec = explode(".", round($measurement, 1));
    $zielEM = floatval("1.".$splitDec[1]);
    if($zielEM <= 1.5){
        foreach($em1 as $em){
            if($em == $zielEM){
                $newMeasurement = round($measurement, 1)-$em;
                echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                    $gauge[] = $em;
                    if($newMeasurement == 0){
                        echo "HELL NO 2";
                    }else{
                        gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                    }
                }
            }else{

                $lastDigitMeasurement = floatval(substr($measurement, -1));
                $lastDigitEM = floatval(substr($em, -1));
                if($lastDigitEM == $lastDigitMeasurement){
                    $newMeasurement = round($measurement, 1)-$em;
                    echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                    if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                        $gauge[] = $em;
                        if($newMeasurement == 0){
                            echo "HELL NO 2";
                        }else{
                            gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                        }
                    }
                }
            }
        }
    }else{
        $nextEM = $zielEM-0.5;
        foreach($em1 as $em){
            if($em == $nextEM){
                $newMeasurement = round($measurement, 1)-$em;
                echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
                if(decimalPlaces($newMeasurement) == 1 || decimalPlaces($newMeasurement) == 0){
                    $gauge[] = $em;
                    if($newMeasurement == 0){
                        echo "HELL NO 2";
                    }else{
                        gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
                    }
                }
            }else{
                $lastDigitMeasurement = floatval("2.".substr($measurement, -1));
                //Solve problem here...


            }
        }

    }
}

if($dp == 0){
    foreach($em0 as $em){
        $em = round($em, 0);
        $newMeasurement = round($measurement, 0) - $em;
        if($newMeasurement >= 0){
            echo "Neuer Messwert: ".$newMeasurement." nach Abzug des Endmasses: ".$em."<br />";
            $gauge[] = $em;
            gaugeBlocks($newMeasurement, $em0, $em1, $em2, $em3);
        }
        if($newMeasurement == 0){
            exit;               
        }
    }
}

return; 
}

echo "<a href='menu.php'>Zurück</a><br />";
echo "<br />";
echo $_POST["mass"];
echo "<br />";



$tray = array();
if($_POST["halle"] == 1){
    $tray = ["W7", "W8"];
}
if($_POST["halle"] == 2){
    $tray = ["W4", "W10"];
}

$em3 = ["1.005"];
$em2 = array();
$em1 = array();
$em0 = array();

$wert = 1;
$em1 = [0.5];
$em0[] = $wert;
while($wert<1.5){
    $wert = $wert+0.01;
    if(decimalPlaces($wert) == 2){
        $em2[] = $wert;
    }else{
        $em1[] = $wert;
    }
}
$wert = 1.5;
while($wert<25){
    $wert = $wert+0.5;
    if(decimalPlaces($wert) != 0){
        $em1[] = $wert;
    }else{
        $em0[] = $wert;
    }
}
$wert = 25;
while($wert<100){
    $wert = $wert+25;
    $em0[] = $wert;
}

/*
 * Alle Möglichen Stückelungen mit vorhandenen Maßen
 */
$measurement = floatval(str_replace(',', '.', $_POST['mass']));
$usedBlocks = array();
$em3 = array_reverse($em3);
foreach(array_keys($em3) as $em){
    $em3[$em] = round($em3[$em], 3);
}

$em2 = array_reverse($em2);
foreach(array_keys($em2) as $em){
    $em2[$em] = round($em2[$em], 2);
    if(($em2[$em] == 1.37)){
        unset($em2[$em]);
    }
}



$em1 = array_reverse($em1);
foreach(array_keys($em1) as $em){
    $em1[$em] = round($em1[$em], 1);
    if(($em1[$em] == 1.4)){
        unset($em1[$em]);
    }
}

$em0 = [100, 75, 50, 25, 24, 23, 22, 21, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 2, 1];
foreach(array_keys($em0) as $em){
    $em0[$em] = round($em0[$em], 0);
}


$usedBlocks[] = gaugeBlocks($measurement, $em0, $em1, $em2, $em3);

?>
10
  • How are the available gauge blocks determined? Commented Aug 18, 2015 at 21:02
  • 2
    Show your current code, so we see a bit more what you are trying to do Commented Aug 18, 2015 at 21:03
  • 2
    Find the largest available gauge that's less than the measurement. Add it to the result list and subtract it from the measurement. Repeat this until you have no more available gauges blocks. Commented Aug 18, 2015 at 21:04
  • sound like an interview problem Commented Aug 18, 2015 at 21:07
  • Maybe my question is too complex: If I have the number 2.9 and an array with different float-values like array {1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, 1.49, 1.5, ...} how can I check which combinations eqal 2.9, e. g.: 2.9 = 1.41 + 1.49 or 2.9 = 1.42 + 1.48 ... Commented Aug 18, 2015 at 21:08

1 Answer 1

1

For instance an gaugeArray = [1, 4, 11.3, 48.6];

There are 4 elements in the array 2^(4) = 16 possible outcomes.

Combination denoted by binary bit:

(1) 0000 (2) 0001 (3) 0010 (4) 0011 (5) 0100 (6) 0101 (7) 0110 (8) 0111 (9) 1000 (10)1001 (11)1010 (12)1011 (13)1100 (14)1101 (15)1110 (16)1111

So, you can try:

<?php

$gaugeString = filter_input(INPUT_GET, 'gauges');
$desired = filter_input(INPUT_GET, 'desired');

$gaugeArray = array();
$need2RunRoutine = false;
$desiredValue  = 12.6;
if(isset($gaugeString) && isset($desired))
{
	$gaugeStringSplits = explode(",", $gaugeString);
	for($i=0; $i<count($gaugeStringSplits); $i++)
	{
		array_push($gaugeArray, floatval($gaugeStringSplits[$i]));
	}
	$desiredValue  = floatval($desired);
	$need2RunRoutine = true;
}
else
{
	$gaugeArray = array(1, 4, 11.3, 48.6);
}
$gaugeInputString = "";
for($i=0; $i<count($gaugeArray); $i++)
{
	$gaugeInputString .= ($gaugeArray[$i].', ');
}
$gaugeInputString = trim($gaugeInputString, ',');
$gaugeInputString = trim($gaugeInputString, ', ');
echo '<form method="GET">Enter gauges(seperated by ,):<br><input type="text" name="gauges" value="'.$gaugeInputString.'"><br>Enter Desired Length:<br><input type="text" name="desired" value="'.$desiredValue.'"><br><input type="submit"></from>';
if($need2RunRoutine)
{
	$bitSelector = array();
	for($i=0; $i<count($gaugeArray); $i++)
	{
		array_push($bitSelector, (0x01<<$i) );
	}
  
	$possibleOutcomesCount = pow(2,count($gaugeArray));
	//echo '$possibleOutcomesCount: '.$possibleOutcomesCount;
	$possibleCombinations = array();  //will contain all possible outcomes

	for($i=0; $i<$possibleOutcomesCount; $i++)     //16  combinations
	{
  		$combineValue = 0;
  		for($j=0; $j<count($gaugeArray); $j++)
  		{
    		if( ($i & $bitSelector[$j]) == $bitSelector[$j])
    		{
      			$combineValue  += $gaugeArray[$j];
    		}
  		}
		//echo '<br>'.$combineValue.'<br>';
  		array_push($possibleCombinations, $combineValue);
	}

	//after this you need to select the value which is most close to your desired value from $possibleCombinations
	$bestMatch = -1;
	$matchIndex = -1;
	for($i=0; $i<count($possibleCombinations); $i++)
	{
  		if( ($bestMatch < $possibleCombinations[$i]) && ($possibleCombinations[$i] <= $desiredValue) )
    	{
      		$bestMatch = $possibleCombinations[$i];
			$matchIndex = $i;
    	}
	}
	if($matchIndex >= 0)
	{
		echo '<br><br><br>Best Match value: '.$bestMatch.'<br>';
		$outputString = '';
		for($i=0; $i<count($bitSelector); $i++)
		{
			if(($matchIndex & $bitSelector[$i]) == $bitSelector[$i])
			{
				$outputString .= ($gaugeArray[$i].'+ ');
			}
		}
		$outputString = trim($outputString, '+ ');
		$outputString .= ' = '.$bestMatch.' which is most close to desired value '.$desiredValue;
		echo $outputString;
	}
	else
	{
		echo 'No gauge conbination can give that desired value.';
	}
	
}
?>

Now $possibleCombinations contains all possible value. You need to select the one which is most close and smaller or equals to the desired value.

Sign up to request clarification or add additional context in comments.

2 Comments

Nice answer! I've never worked with this "bitSelector"-thing. But as soon as I understood what it does and how it works and when I were able to adopt it to my problem, I will mark your answer as accepted! Do you have further information about this bit-thing? Any links etc.?
Fixed some typo in the code, here is a more generic example

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.