i need to be able to validate CUSIP numbers based on thier check digit. I have the psudocode for the process thanks to wikipedia, but i have so far been unable to replicate it in PHP.
Psudocode can be found here.
My PHP:
<?php
/**
* function to return the check digit value of a cusip
* #param $cusip
* the cusip for processing.
* #return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '#':
$v = 37;
watchdog("case #: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * # or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + ($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}
?>
watchdog is simply me logging the process.
Passing in a CUSIP of: 98986T108 which has a check digit value of 8, actually returns a value of 98986T104 (check digit value of 4).
so:
<?php
print cusip_checksum('98986T108');
?>
should return 8, it returns 4.
Can anyone spot the reason for this?
Wrap the division in a floor() function and you are there:
$sum = $sum + floor($v / 10) + ($v % 10);
Now a Q in the CUSIP will have a value of 26. This will add 2 and 6 to the $sum instead of adding 2.6 and 6.
Here's the final function with the correction. I've run this through a Reuters extract of 17614 CUSIPs and there were 11 that did not match up. That's about the level of error I usually see from Reuters data so I have confidence in the routine.
/**
* function to return the check digit value of a cusip
* #param $cusip
* the cusip for processing.
* #return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '#':
$v = 37;
watchdog("case #: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * # or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + floor($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}
Related
I'm trying to do a syntax cast where I have a javascript function that calculates the check digit from an input number.
where the variables:
input - is the input value (Example: 200300)
num_digits - is the number of digits (if defined 1, its respective digit will be 7; already defined it 2, its respective digit will be 70. According to the input value)
limit - is the multiplication limit (in my case I need it to be multiplied by/up to 9)
x10 - in this case being true or false, being true the digit will be multiplied by 10
all variables mentioned above refer to my JavaScript function:
function calcDigitMod11(input, num_digits, limit, x10) {
var mult, sum, i, n, digit;
if (!x10) num_digits = 1;
for (n = 1; n <= num_digits; n++) {
sum = 0; mult = 2;
for (i = (input.length - 1); i >= 0; i--) {
sum += (mult * parseInt(input.charAt(i)));
if (++mult > limit) mult = 2;
}
if (x10) {
digit = ((sum * 10) % 11) % 10;
} else {
digit = sum % 11;
if (digit == 10) digit = 'x';
}
input += (digit);
}
return input.substring((input.length - num_digits), num_digits);
}
in short, my big problem is to create this same function in the php syntax
If you print the function's return on the console, passing the following parameters: calcDigitMod11(200300, 1, 9, true); your return must be the check digit
7
giving an applied...
"tried" to convert syntaxes using the same variables, parameters, among others
function calcDigitMod11($input, $num_digits, $limit, $x10) {
$mult; $sum; $i; $n; $digit;
if (!$x10) $num_digits = 1;
for ($n = 1; $n <= $num_digits; $n++) {
$sum = 0; $mult = 2;
for ($i = (strlen($input) - 1); $i >= 0; $i--) {
$sum += ($mult * (int)$input[$i]);
if ((++$mult) > $limit) $mult = 2;
}
if ($x10) {
$digit = (($sum * 10) % 11) % 10;
} else {
$digit = $sum % 11;
if ($digit == 10) $digit = 'x';
}
$input += ($digit);
}
return substr($input, strlen($input) - $num_digits, $num_digits);
}
I wrote an echo calcDigitMod11(200300, 1, 9, true); but it returns the digit to me.
0
I didn't find where the mistaken point x is, I don't know if I'm running away from logic! Here is a table of the JavaScript function of the true digits according to the input value:
calcDigitMod11(200300, 1, 9, true); is return 7
calcDigitMod11(200301, 1, 9, true); is return 5
calcDigitMod11(200302, 1, 9, true); is return 3
calcDigitMod11(200303, 1, 9, true); is return 1
In PHP, you can retrieve characters using index values only for strings. Example:
$str = "98765";
echo $str[1]; // will return 8
If we do the same for integers it will throw a warning.
$num = 98765;
echo $num[1];
Warning: Trying to access array offset on value of type int
To enable errors/warnings in your script, add the below code at the top of your php file
error_reporting(E_ALL);
ini_set('display_errors', '1');
Now, to fix your algorithm, we can use str_split to convert the integer values into an array before using index to extract digits.
<?php
function calcDigitMod11($input, $num_digits, $limit, $x10) {
$mult; $sum; $i; $n; $digit;
if (!$x10) $num_digits = 1;
for ($n = 1; $n <= $num_digits; $n++) {
$sum = 0; $mult = 2;
$input_arr = str_split($input); // Convert string to an array
for ($i = (strlen($input) - 1); $i >= 0; $i--) {
$sum += ($mult * $input_arr[$i]); // Use array to fetch digits
if ((++$mult) > $limit) $mult = 2;
}
if ($x10) {
$digit = (($sum * 10) % 11) % 10;
} else {
$digit = $sum % 11;
if ($digit == 10) $digit = 'x';
}
$input += ($digit);
}
echo "<br/><br/>True Digit=$digit<br/>";
return substr($input, strlen($input) - $num_digits, $num_digits);
}
echo "Output=" . calcDigitMod11(200300, 1, 9, true);
echo "Output=" . calcDigitMod11(200301, 1, 9, true);
echo "Output=" . calcDigitMod11(200302, 1, 9, true);
echo "Output=" . calcDigitMod11(200303, 1, 9, true);
?>
Output:
True Digit=7
Output=7
True Digit=5
Output=6
True Digit=3
Output=5
True Digit=1
Output=4
Working Demo
Reference of my Question
how can I get the closest pairs from this array
// Input
$required = 1.3;
$array_result = [0.6, 0.5, 0.8, 0.7];
// Algorithm
$remaining = $required;
$whichtakes = [];
foreach($array_result as $i => $a) {
foreach(array_slice($array_result, $i+1) as $b) {
$test = $required - $a - $b;
if ($test >= 0 and $test < $remaining) {
$remaining = $test;
$whichtakes = [$a, $b];
}
}
}
// Output
print_r($whichtakes); // [0.5, 0.8]
print_r($remaining); // 0
Thanks to trincot
its working fine with pairs but there is little change , Algorithm is getting pairs but i want array which match my result array, just need this little change. if $required = 1.3 change to $required = 1.8 now it should give me array 0.6,0.5,0.7 and if $required = 1.9 now it should give me array 0.6,0.5,0.7 and 0.1 remaining
This algorithm is part of dynamic programming. Here is the modified code.
$res = array();
function isSubsetSum($set, $n, $sum)
{
if ($sum == 0)
return true;
if ($n == count($set) - 1 && $sum != 0)
return false;
if ($set[$n + 1] > $sum) {
return isSubsetSum($set, $n + 1, $sum);
}
return isSubsetSum($set, $n + 1, $sum) ||
isSubsetSum($set, $n + 1, $sum - $set[$n + 1]);
}
$set = array(0.6, 0.5, 0.8, 0.7);
$sum = 1.8;
$n = 0;
$remaining = 0;
while (!isSubsetSum($set, 0, $sum)) {
$remaining += 0.1;
$sum -= 0.1;
}
echo $res; // the array result
echo $remaining;
This code doesn't store the array subset. You can store the array result inside the function. I don't know how to optimize this algorithm though.
For more information about dynamic programming, check this link
I need to divide an integer value into x parts (dynamic) using php inside a for loop (Note:Both the number to be split and the split value are dynamic)
for eg: I have a value 127 and divide it into 2parts it would be 63 and 64.
$number = y; //for example is 127
$parts = x; //for example is 2
for($i=1;$i<$parts;$i++){
//first iteration should output 63
//second iteration should output 64 (the last iteration should be always higher is the $number is not divisible by $parts)
}
Check out this example. I use the modulo operator. This works whether it's an even or odd number. You could wrap this all in a function also.
$x = 127;
$a = 0;
$b = 0;
$a = floor($x/2);
$b = ($x % 2) + $a;
echo "A: " . $a . "| B: " . $b; //A: 63| B: 64
Try it in a function.
function remainders($x, $num) {
$results = array();
$firstOp = floor($x / $num);
for($a = 1; $a <= $num; $a++) {
if($a != $num) {
$results[] = $firstOp;
}
else {
if($x % 2 == 1) {
$results[] = $firstOp + 1;
}
else {
$results[] = $firstOp;
}
}
}
return $results;
}
Then you can iterate through the returned array or do what you want.
$splitNum = remainders(183, 4); //split the number 183 in 4 parts.
foreach($splitNum as $var) { echo $var . ", "; }
Try this:
$number = 127; //for example is 127
$parts = 3; //for example is 3
$sep = ", ";
$n=floor($number/$parts);
for($i=1;$i<=$parts;$i++){
if ($i==$parts) {
$n=$number-($n*($i-1));
$sep="";
}
echo $n.$sep;
}
I use the following to find out the common divisors.
But in some case the count of divisors are not satisfied.
My Code :
$x = 66928;
$y = 66992;
$c_a = [];
$c_b = [];
$d = 1;
while ($d_a <= $x) {
if (is_int($x / $d)) $c_a[] = $d;
$d++;
}
$d = 1;
while ($d_b <= $y) {
if (is_int($y / $d)) $c_b[] = $d;
$d++;
}
echo count($c_a);
echo count($c_b);
// Output
$c_a = 20;
$c_b = 20;
Because, in some cases, it won't work.
Is this type of calculation is right ?
or any suggestions ?
As per asked in comment, to count the common factors of the two no. will be as like this.
<?php
$a = 66928;
$b = 66992;
$min = ($a < $b ) ? $a : $b;
$commomn_factors_count = 0;
for ($i = 1; $i < $min/2; $i++) {
if (($a%$i==0) && ($b%$i==0)) {
$commomn_factors_count++;
}
}
var_dump($commomn_factors_count);
You can you this code to get the fastest result to find the number of common divisors between two numbers:
// Function to calculate gcd of two numbers
function gcd($a, $b)
{
if ($a == 0)
return $b;
return gcd($b % $a, $a);
}
/* Function to calculate all common
* divisors of two given numbers
* a, b --> input integer numbers
*/
function commDiv($a, $b)
{
// find gcd of a, b
$n = gcd($a, $b);
// Count divisors of n.
$result = 0;
for ($i = 1; $i <= sqrt($n);
$i++)
{
// if 'i' is factor of n
if ($n % $i == 0)
{
// check if divisors
// are equal
if ($n / $i == $i)
$result += 1;
else
$result += 2;
}
}
return $result;
}
// Driver Code
$a = 10; $b = 15;
echo(commDiv($a, $b));
Simple question, how do I get every option when dividing a number? For example:
24 by 6 returns 6, 12, 18, 24
24 by 4 returns 4, 8, 12, 16, 20, 24
24 by 5 returns false
I've got a number in my database, for example 2, and my counter, for example 14. That means every time my counter hits the second number, I want to fire my event. So I thought, if I have the solutions 2, 4, 6, etc, and my counter is equal to one of the solutions, I can fire my event.
It's rather trivial to make.
<?php
/**
* #param int $number The beginning number
* #param int $divider The number dividing by
*
* #return array
* #throws Exception In case $number is not divisible by $divider
*/
function get_number_sequence($number, $divider) {
//In case $number is not divisible by $divider, throw an Exception.
if ($number % $divider !== 0) {
throw new Exception("$number is not divisible by $divider");
}
//Return an array from $divider to $number in steps of $divider.
$result = range($divider, $number, $divider);
return $result;
}
/*
* Testing begins
*/
try {
echo "<pre>";
echo implode(", ", get_number_sequence(24, 4)) . PHP_EOL;
echo implode(", ", get_number_sequence(24, 6)) . PHP_EOL;
echo implode(", ", get_number_sequence(24, 5)) . PHP_EOL;
echo "</pre>";
}
catch (Exception $e) {
echo "Invalid: " . $e->getMessage();
}
Some Points
Don't return false if something exceptional happens, use an Exception as shown in the example.
Use the modulus operator to determine if the number is divisible or not.
Return an array, not a string. It's easier to work with.
should be easy
do a modulus on X by Y . If 0 then do a division on X by Y. create a loop which will run from 1 to (division on X by Y) and output Y multiplied by the loop counter
function steps($target,$step) {
if (($target % $step) != 0)
return FALSE;
$steps = range($step,$target,$step);
return $steps;
}
$target = 24;
for ($step = 2; $step < 13; ++$step) {
echo '$step = ',$step,PHP_EOL;
$steps = steps($target,$step);
var_dump($steps);
}
function findQuotients($number, $divider)
{
$arr = array();
if($number % $divider != 0)
{
//return "false";
}
else
{
$loop = $number / $divider;
//$output="";
for($i = 1; $i <= $loop; $i++)
{
//$output .= $i * $divider. " ";
array_push($arr, $i * $divider);
}
}
return $arr;
}
echo print_r(findQuotients(24, 6));
echo print_r(findQuotients(24, 4));
echo print_r(findQuotients(24, 5));
Try this
$number = 24;
$divider = 6;
if($number % $divider != 0 )
{
return false;
}
$div = $number / $divider;
for($i = 1; $i <= $div; $i++)
{
echo $i*$divider;
}
The following snippet will do the trick. It's a simple loop to iterate until $num is <= 0. $num will be subtracted by the divider and each turn the next multiple of $div will be stored as a "divider step".
$num = 24;
$div = 4;
if ($num % $div != 0) {
exit('invalid');
}
$divider = array();
for ($i = 1; $num > 0; $i++) {
$divider[] = ($i * $div);
$num -= $div;
}
echo 'in: ' . $num . '<br />';
echo 'div: ' . $div . '<br />';
echo '<pre>';
print_r($divider);
exit;
based on your description you want to multiply a number and then on a given result you want to white a function:
$num = 6;
$counter = 2;
$solution = 24;
while ($num * $counter) {
$result= $num * $counter;
if ($result = $solution) {
echo $result;
// here would go your event
break;
}
}