Using VBA code I found in a spreadsheet to adapt to an online PHP application. The code uses the bisection method in mathematics to find optimal value for a calculation required to price options.
Upper = estimate_upper
Lower = estimate_lower
UUpper = container
Start_Iteration:
IterationCountE = 0.000000001
While (Upper - Lower) > IterationCountE
Mid = (Upper + Lower) / 2
c1 = calculations1...
c2 = calculations2...
If (c2 - c1) > 0 Then
Lower = Mid
Else
Upper = MId
End If
Wend 'Ends the while loop
If (Round(Mid, 4) = Round(UUpper, 4)) Then
Upper = 2 * UUpper
UUpper = Upper
GoTo Start_Iteration
End If
Function = Mid
For most part, I understand the mechanics of the iteration. My attempted PHP conversion is as follows:
$IterationCountE = 0.00000000001;
while ( ($Upper - $Lower) > $IterationCountE ) {
$Mid = ($Upper + $Lower) / 2;
$c1 = calculation1();
$c2 = calculation2();
if ( ($c2 - $c1) > 0 ) {
$Lower = $Mid;
} else {
$Upper = $Mid;
}
if (round($Mid, 4) == round($UUpper, 4)) {
$Upper = 2 * $UUpper;
$UUpper = $Upper;
}
}
return $Mid;
Is this the best way to approach an similar iteration in PHP? Would it be better to wrap the iteration in a function and refer back to it like in the VBA code?
I do not get the same value results when comparing the PHP output to the value from a macro.
I tried this sudoku solver http://www.emanueleferonato.com/2008/12/09/sudoku-creatorsolver-with-php/. It works fine.
Also see this spreadsheet to see more detail in calculation : spreadsheet
I understand how the row and col scanning. From the board, we know that:
index = 9*row + col
row = floor(index/9)
col = index % 9
And for the block, because it build from 3x3 board so the formula: block_index = 3*row_block + col_row. Because per block there are 3 rows and cols, so the formula for row_block = floor(row/3) and col_block = floor(col/3). From here we can conclude that:
block_index = 3*row_block + col_row
block_index = 3(floor(row/3)) + floor(col/3)
block_index = floor(row/3)*3 + floor(col/3)
This could explain for these function :
return_row
retun_col
return_block
is_possible_row
is_possible_col
But I cannot understand about is_possible_block function. Here is the function:
function is_possible_block($number,$block,$sudoku){
$possible = true;
for($x = 0;$x <= 8;$x++){
if($sudoku[floor($block / 3) * 27 + $x % 3 + 9 * floor($x / 3) + 3 * ($block % 3)] == $number){
$possible = false;
}
}
return $possible;
}
What I know about is_possible_block function is:
floor($block / 3) * 27 + $x % 3 + 9 * floor($x / 3) + 3 * ($block % 3)
= 9row+col
= 9(floor($block/3)*3 + floor($x/3)) + ($x%3 + 3*($block%3))
row = 3row_block+row_x_block
floor($block/3) = row_block
floor($x/3) = row_x_block
col = 3col_block+col_x_block
How col = 3col_block+col_x_block , because what I know, the formula should be like this : col = 3row_block+col.
I know col_x_block mean column position on 0-8 block. And row_block mean row position on 0-2 block.
How do you explain this formula? Thanks
UPDATE
Now I know. floor($block/3)*3 and 3*($block%3) determine top left corner in block. Then floor($x / 3) and $x % 3 moves each cell in the block.
I use it in c++
for(int k = ((x - 1) / 3) * 3 + 1; k < ((x - 1) / 3) * 3 + 4; k++
because of "x" is integer "/" operation return int value.
maybe 3(floor($block-1/3)) can help you.
I need to implement a function that interpolates an exponential curve from three points, but I'm not sure how to do it.
I have a graph that has the Y axis as percentage, 0 to 100% and X as 0 to 10.
The only points that I know are (50,7), (100,10) and (0,0).
I know I can create an array that has the percentages and values and loop through it, but this does not feel like the "right" way to do it. Is there a more direct algorithm?
I would use the formula :
partial : total = % : 100
partial (the value) = (total * %) / 100
Code
<?php
$points = array("8%,67%","36%,74%","73%,13%");
function return_value($percentage,$total) {
$value = ($total * $percentage) / 100.0;
return $value;
}
function evaluate_points($points) {
$max_x = 100.0; // As float value
$max_y = 10.0; // As float value
for ($point = 0; $point < count($points); $point++) {
//Replace the % sign
$points[$point] = str_replace("%", "", $points[$point]);
$point_percentages = explode(",", $points[$point]);
$x_percentage = $point_percentages[0];
$y_percentage = $point_percentages[1];
echo("The value for x is : ".return_value($x_percentage,$max_x) ."<br>");
echo("The value for y is : ".return_value($y_percentage,$max_y). "<br><br>");
}
}
evaluate_points($points);
?>
Output
I am using the following PHP code to calculate a CRN for BPay:
<?php
function LuhnCalc($number) {
$chars = array_reverse(str_split($number, 1));
$odd = array_intersect_key($chars, array_fill_keys(range(1, count($chars), 2), null));
$even = array_intersect_key($chars, array_fill_keys(range(0, count($chars), 2), null));
$even = array_map(function($n) { return ($n >= 5)?2 * $n - 9:2 * $n; }, $even);
$total = array_sum($odd) + array_sum($even);
return ((floor($total / 10) + 1) * 10 - $total) % 10;
}
print LuhnCalc($_GET['num']);
?>
However it seems that BPAY is version 5 of MOD 10, for which I can't find any documentation. It seems to not be the same as MOD10.
The following numbers where tested:
2005,1597,3651,0584,9675
bPAY
2005 = 20052
1597 = 15976
3651 = 36514
0584 = 05840
9675 = 96752
MY CODE
2005 = 20057
1597 = 15974
3651 = 36517
0584 = 05843
9675 = 96752
As you can see, none of them match the BPAY numbers.
This PHP function will generate BPay reference numbers based on the mod10 version 5 algorithm.
Who knows why BPay can't add this to their website. I only found an explanation by googling finding the algorithm being called "MOD10V05" instead of "Mod 10 version 5".
function generateBpayRef($number) {
$number = preg_replace("/\D/", "", $number);
// The seed number needs to be numeric
if(!is_numeric($number)) return false;
// Must be a positive number
if($number <= 0) return false;
// Get the length of the seed number
$length = strlen($number);
$total = 0;
// For each character in seed number, sum the character multiplied by its one based array position (instead of normal PHP zero based numbering)
for($i = 0; $i < $length; $i++) $total += $number{$i} * ($i + 1);
// The check digit is the result of the sum total from above mod 10
$checkdigit = fmod($total, 10);
// Return the original seed plus the check digit
return $number . $checkdigit;
}
Here's a way of implementing the "MOD10V5" algorithm (or "mod 10 version 5") using a t-sql user defined function in SQL server. It accepts a Customer ID up to 9 characters long, and return an 11 character CRN (Customer Reference Number).
I also prepended a version number onto the start of my CustomerID, you could do this too if you think you might end up changing it in the future.
CREATE Function [dbo].[CalculateBPayCRN]
(
#CustomerID nvarchar(9)
)
RETURNS varchar(11)
AS
BEGIN
DECLARE #NewCRN nvarchar(11)
DECLARE #Multiplier TINYINT
DECLARE #Sum int
DECLARE #SubTotal int
DECLARE #CheckDigit int
DECLARE #ReturnVal BIGINT
SELECT #Multiplier = 1
SELECT #SubTotal = 0
-- If it's less than 9 characters, pad it with 0's, then prepend a '1'
SELECT #NewCRN = '1' + right('000000000'+ rtrim(#CustomerID), 9)
-- loop through each digit in the #NewCRN, multiple it by the correct weighting and subtotal it:
WHILE #Multiplier <= LEN(#NewCRN)
BEGIN
SET #Sum = CAST(SUBSTRING(#NewCRN,#Multiplier,1) AS TINYINT) * #Multiplier
SET #SubTotal = #SubTotal + #Sum
SET #Multiplier = #Multiplier + 1
END
-- mod 10 the subtotal and the result is our check digit
SET #CheckDigit = #SubTotal % 10
SELECT #ReturnVal = #NewCRN + cast(#CheckDigit as varchar)
RETURN #ReturnVal
END
GO
Modula 10 V1 in PHP. Tested against my Windows dataflex routine and it is the same.
function generateBpayRef($number) {
//Mod 10 v1
$number = preg_replace("/\D/", "", $number);
// The seed number needs to be numeric
if(!is_numeric($number)) return false;
// Must be a positive number
if($number <= 0) return false;
$stringMemberNo = "$number";
$stringMemberNo = str_pad($stringMemberNo, 6, "0", STR_PAD_LEFT);
//echo " Padded Number is $stringMemberNo ";
$crn = $stringMemberNo;
for($i=0;$i<7;$i++){
$crnval = substr($crn,(5-$i),1);
$iPartVal = $iWeight * $crnval;
if($iPartVal>9){
//echo " Greater than 9: $iPartVal ";
$firstChar = substr($iPartVal,0,1);
$secondChar = substr($iPartVal,1,1);
$iPartVal=$firstChar+$secondChar;
//$iPartVal -= 9;
}
$iSum+=$iPartVal;
$iWeight++;
if ($iWeight>2){$iWeight=1;}
//echo " CRN: $crnval ] Weight: $iWeight ] Part: $iPartVal ] SUM: $iSum ";
}
$iSum %= 10;
if($iSum==0){
//echo " zero check is $iSum ";
//return $iSum;
}
else{
//return 10-$iSum;
$iSum=(10-$iSum);
}
//echo " Check is a $iSum ";
$BpayMemberNo = $stringMemberNo . $iSum ;
echo " New: $BpayMemberNo ";
return ($BpayMemberNo);
}
Here is a ruby class I whipped up quickly for Mod 10 v5
module Bpay
class CRN
attr_accessor :number, :crn
class << self
def calculate_for(number)
new(number).crn
end
end
def initialize(number)
#number = number
calculate
end
def calculate
raise ArgumentError, "The number '#{number}' is not valid" unless valid?
digits = number.to_s.scan(/\d/).map { |x| x.to_i }
raise ArgumentError, "The number '#{number}' must be at least 2 digits in length" if digits.size < 2
check_digit = digits.each_with_index.map { |d, i| d * (i + 1) }.inject(:+) % 10
#crn = "#{number}#{check_digit}"
end
def valid?
return false unless !!Integer(number.to_s) rescue false
return false if number.to_i <= 0
true
end
end
end
This is in C#, but this is what I have so far for BPay check digit generation:
private void btnBPayGenerate_Click(object sender, EventArgs e)
{
var originalChars = txtBPayNumber.Text.ToCharArray();
List<int> oddDigits = new List<int>();
List<int> evenDigits = new List<int>();
int oddTotal = 0, evenTotal = 0, total = 0, checkDigit ;
const int oddMultiplier = 3;
const int modulus = 10;
bool isOdd = true;
for (int x = 0; x < originalChars.Length; x++)
{
if(isOdd)
oddDigits.Add(Int32.Parse(originalChars[x].ToString()));
else
evenDigits.Add(Int32.Parse(originalChars[x].ToString()));
isOdd = !isOdd;
}
foreach (var digit in oddDigits)
oddTotal += digit;
foreach (var digit in evenDigits)
evenTotal += digit;
oddTotal = oddTotal * oddMultiplier;
total = oddTotal + evenTotal;
checkDigit = (modulus - (total % modulus));
lblBPayResult.Text = txtBPayNumber.Text + checkDigit.ToString();
}
I haven't completed testing this yet, I will post back once BPAY get back to me.
EDIT: try this: https://gist.github.com/1287893
I had to work out a version for javascript, this is what I came up with. It correctly generates the expected numbers in the original question.
var startingNumber = 2005;
var reference = startingNumber.toString();
var subTotal = 0;
for (var x = 0; x < reference.length; x++) {
subTotal += (x + 1) * reference.charAt(x);
}
var digit = subTotal % 10;
var bpayReference = reference + digit.toString();
Here is a function I created using vb.net to calculate a mod 10 version 5 check digit
Private Function CalcCheckDigit(ByRef psBaseNumber As String) As String
Dim lCheckDigit, iLoop As Integer
Dim dCalcNumber As Double
lCheckDigit = 0
dCalcNumber = 0
For iLoop = 0 To (psBaseNumber.Length - 1)
lCheckDigit = lCheckDigit + (psBaseNumber.Substring(iLoop, 1) * (iLoop + 1))
Next iLoop
lCheckDigit = lCheckDigit Mod 10
CalcCheckDigit = psBaseNumber & CStr(lCheckDigit)
End Function
How to write a function to determine the population count of a 16-bit
integer using php or javascript. Population count is defined as the number of bits that are
"turned on," or in others, it is the number of 1s in a binary
representation of a number. For example, the binary number 0b0000 has
a population count of 0 because there aren't any 1 bits. 0b0101 has a
population count of 2, because 2 bits turned on; 0b1110 has a
population count of 3. 0b1111111111111111 has a population count if 16
because there are sixteen 1 bits. Your function should accept an INTEGER
argument and return an INTEGER containing its population count. Example:
f(0) = 0
f(1) = 1
f(2) = 1
f(3) = 2
f(4) = 1
f(5) = 2
Using bitwise and and right shift
function count(n){
c =0;
while(n){
c += n&1;
n = n>>1;
}
return c;
}
The badass way?
var x=0xfffe;
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
x += (x >> 8);
x += (x >> 16);
alert(x & 0x0000003f); //15
Not necessarily badass, but it works...
<?php
$number = 3;
echo "Number: " . $number . "\n";
$bin_number = decbin($number);
$population_count = 0;
echo "Binary String Conversion: " . $bin_number . "\n";
for ($i = strlen($bin_number) - 1; $i >= 0; --$i) {
$population_count += $bin_number[$i];
}
echo "Population Count: " . $population_count . "\n";
?>