PHP FFT module error - php

I wrote a FFT (Fast Fourier Transform) module for PHP recently. When I tried to test it, It always throws an error that the array $this->reverseTable has some index not defined. I got no clue of how to solve this problem.
Here's the PHP code:
<?php
class FourierTransform {
public $bufferSize;
public $sampleRate;
public $bandwidth;
public $spectrum = array();
public $real = array();
public $imag = array();
public $peakBand = 0;
public $peak = 0;
public function __construct($bufferSize,$sampleRate){
$this->bufferSize = $bufferSize;
$this->sampleRate = $sampleRate;
$this->bandwidth = 2 / $bufferSize * $sampleRate / 2;
}
public function getBandFrequency($index){
return $this->bandwidth * $index + $this->bandwidth / 2;
}
public function calculateSpectrum(){
$bSi = 2 / $this->bufferSize;
for($i = 0,$N = $this->bufferSize/2; $i < $N; $i++){
$rval = $this->real[$i];
$ival = $this->imag[$i];
$mag = $bSi * sqrt($rval * $rval + $ival * $ival);
if($mag > $this->peak){
$this->peakBand = $i;
$this->peak = $mag;
}
$this->spectrum[$i] = $mag;
}
}
}
class FFT extends FourierTransform {
public $reverseTable = array();
public $sinTable = array();
public $cosTable = array();
public function __construct($bufferSize,$sampleRate){
parent::__construct($bufferSize,$sampleRate);
$limit = 1;
$bit = $bufferSize >> 1;
while($limit < $bufferSize){
for($i = 0; $i < $limit; $i++){
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
}
$limit = $limit << 1;
$bit = $bit >> 1;
}
for($i = 0; $i < $bufferSize; $i++){
$this->sinTable[$i] = sin(-M_PI / $i);
$this->cosTable[$i] = cos(-M_PI / $i);
}
}
public function foward($buffer){
$k = floor(log($this->bufferSize,2));
if(pow(2,$k) !== $this->bufferSize) throw new Exception('Invalid buffer size, must be a power of 2.');
if($this->bufferSize !== count($buffer)) throw new Exception('Supplied buffer is not the same size as defined FFT.');
$halfSize = 1;
for($i = 0; $i < $this->bufferSize; $i++){
$this->real[$i] = $buffer[$this->reverseTable[$i]];
$this->imag[$i] = 0;
}
while($halfSize < $this->bufferSize){
$phaseShiftReal = $this->cosTable[$halfSize];
$phaseShiftImag = $this->sinTable[$halfSize];
$currentPhaseShiftReal = 1;
$currentPhaseShiftImag = 0;
for($fftStep = 0; $fftStep < $halfSize; $fftStep++){
while($fftStep < $this->bufferSize){
$off = $fftStep + $halfSize;
$tr = ($currentPhaseShiftReal * $this->real[$off]) - ($currentPhaseShiftImag * $this->imag[$off]);
$ti = ($currentPhaseShiftReal * $this->imag[$off]) + ($currentPhaseShiftImag * $this->real[$off]);
$this->real[$off] = $this->real[$fftStep] - $tr;
$this->imag[$off] = $this->imag[$fftStep] - $ti;
$this->real[$fftStep] += $tr;
$this->imag[$fftStep] += $ti;
$fftStep += $halfSize << 1;
}
$tmpReal = $currentPhaseShiftReal;
$currentPhaseShiftReal = ($tmpReal * $phaseShiftReal) - ($currentPhaseShiftImag * $phaseShiftImag);
$currentPhaseShiftImag = ($tmpReal * $phaseShiftImag) + ($currentPhaseShiftImag * $phaseShiftReal);
}
$halfSize = $halfSize << 1;
}
$this->calculateSpectrum();
}
}
?>
The test sample is a sine wave at 440Hz.
When I tried to run the code, it throws this error
Notice: Undefined offset: 0 in C:\Program Files
(x86)\EasyPHP-12.1\www\fft.php on line 48
continuously.
The array that has problem has data like this:
Array
(
[1] => 512
[2] => 256
[3] => 768
[4] => 128
[5] => 640
[6] => 384
[7] => 896
[8] => 64
[9] => 576
[10] => 320
[11] => 832
[12] => 192
[13] => 704
[14] => 448
[15] => 960
[16] => 32
[17] => 544
[18] => 288
[19] => 800
[20] => 160
[21] => 672
[22] => 416
[23] => 928
[24] => 96
[25] => 608
[26] => 352
[27] => 864
[28] => 224
[29] => 736
[30] => 480
[31] => 992
[32] => 16
[33] => 528
[34] => 272
[35] => 784
[36] => 144
[37] => 656
[38] => 400
[39] => 912
[40] => 80
[41] => 592
[42] => 336
[43] => 848
[44] => 208
[45] => 720
...
[978] => 303
[979] => 815
[980] => 175
[981] => 687
[982] => 431
[983] => 943
[984] => 111
[985] => 623
[986] => 367
[987] => 879
[988] => 239
[989] => 751
[990] => 495
[991] => 1007
[992] => 31
[993] => 543
[994] => 287
[995] => 799
[996] => 159
[997] => 671
[998] => 415
[999] => 927
[1000] => 95
[1001] => 607
[1002] => 351
[1003] => 863
[1004] => 223
[1005] => 735
[1006] => 479
[1007] => 991
[1008] => 63
[1009] => 575
[1010] => 319
[1011] => 831
[1012] => 191
[1013] => 703
[1014] => 447
[1015] => 959
[1016] => 127
[1017] => 639
[1018] => 383
[1019] => 895
[1020] => 255
[1021] => 767
[1022] => 511
[1023] => 1023
)
Edit: The previous problem is solved but now another problem is raised. At function forward() it throws an uncaught exception Invalid buffer size, must be a power of 2. Even if the buffer size is right.
Any help will be appreciated.

Assuming that this is the whole class, I presume that the issue lies on this line inside your FFT constructor:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
From what I can tell you declare reverseTable as an array, but this line is the only place in the class where any elements are added to that array, so the fact that you're setting the reverseTable[$i+$limit] element using a never-defined reverseTable[$i] value is going to give you problems in the first first iteration of that while loop when it tries to use the undefined index $i (reverseTable[$i]). You'll have to give reverseTable[0] a value before you enter that loop.

Although you didn't provide where the line was, my guess is it has something to do with this line:
$this->reverseTable[$i + $limit] = $this->reverseTable[$i] + $bit;
This is in your constructor, and this bit especially looks wrong $this->reverseTable[$i] + $bit;. You are asking for the value from the reverseTable array, but this key is not initialized anywhere in the constructor.
I am not sure how to fix this, as it is a logic error on your part.

Related

Number to words in devnagri

I have to display result as
दुई खर्ब सतासी अर्ब अन्ठान्नब्बे करोड नब्बे लाख बाह्र हजार तीन सय पचहत्तर ...
It displays result correctly till five numbers..
But it doesn't display as needed when we use six numbers....
like 111111 .... It displays "एक सय एघार हजार एक सय एघार"
Where as it must be as "एक लाख एघार हजार एक सय एघार" .....
In case of seven and more numbers it throws error....
error 'Undefined offset: 1000000 in.....' ...
<?php
function convert_number_to_words($number) {
$hyphen = '-';
$conjunction = ' ';
$separator = ' ';
$negative = 'negative ';
$decimal = ' point ';
$dictionary = array(
0 => 'शुन्य',
1 => 'एक',
2 => 'दुई',
3 => 'तीन',
4 => 'चार',
5 => 'पाँच',
6 => 'छ',
7 => 'सात',
8 => 'आठ',
9 => 'नौ',
10 => 'दश',
11 => 'एघार',
12 => 'बाह्र',
13 => 'तेह्र',
14 => 'चौध',
15 => 'पन्ध',
16 => 'सोह्र',
17 => 'सत्र',
18 => 'अठार',
19 => 'उन्नाइस',
20 => 'विस',
21 => 'एक्काइस',
22 => 'बाइस',
23 => 'तेइस',
24 => 'चौविस',
25 => 'पच्चिस',
26 => 'छब्बिस',
27 => 'सत्ताइस',
28 => 'अठ्ठाईस',
29 => 'उनन्तिस',
30 => 'तिस',
31 => 'एकत्तिस',
32 => 'बत्तिस',
33 => 'तेत्तिस',
34 => 'चौँतिस ',
35 => 'पैँतिस',
36 => 'छत्तिस',
37 => 'सैँतीस',
38 => 'अठतीस',
39 => 'उनन्चालीस',
40 => 'चालीस',
41 => 'एकचालीस',
42 => 'बयालीस',
43 => 'त्रियालीस',
44 => 'चवालीस',
45 => 'पैँतालीस',
46 => 'छयालीस',
47 => 'सरचालीस',
48 => 'अठचालीस',
49 => 'उनन्चास',
50 => 'पचास',
51 => 'एकाउन्न',
52 => 'बाउन्न',
53 => 'त्रिपन्न',
54 => 'चउन्न',
55 => 'पचपन्न',
56 => 'छपन्न',
57 => 'सन्ताउन्न ',
58 => 'अन्ठाउन्न',
59 => 'उनन्साठी',
60 => 'साठी',
61 => 'एकसट्ठी',
62 => 'बयसट्ठी',
63 => 'त्रिसट्ठी',
64 => 'चौंसट्ठी',
65 => 'पैंसट्ठी',
66 => 'छयसट्ठी',
67 => 'सतसट्ठी',
68 => 'अठसट्ठी',
69 => 'उनन्सत्तरी',
70 => 'सत्तरी',
71 => 'एकहत्तर',
72 => 'बहत्तर',
73 => 'त्रिहत्तर',
74 => 'चौहत्तर',
75 => 'पचहत्तर',
76 => 'छयहत्तर',
77 => 'सतहत्तर',
78 => 'अठहत्तर',
79 => 'उनासी',
80 => 'असी',
81 => 'एकासी',
82 => 'बयासी',
83 => 'त्रियासी',
84 => 'चौरासी',
85 => 'पचासी',
86 => 'छयासी',
87 => 'सतासी',
88 => 'अठासी',
89 => 'उनान्नब्बे',
90 => 'नब्बे',
91 => 'एकान्नब्बे',
92 => 'बयानब्बे',
93 => 'त्रियान्नब्बे',
94 => 'चौरान्नब्बे',
95 => 'पन्चानब्बे',
96 => 'छयान्नब्बे',
97 => 'सन्तान्नब्बे',
98 => 'अन्ठान्नब्बे',
99 => 'उनान्सय',
100 => 'सय',
1000 => 'हजार',
100000 => 'लाख',
10000000 => 'करोड',
1000000000 => 'अर्ब',
100000000000 => 'खर्ब'
);
if (!is_numeric($number)) {
return false;
}
if (($number >= 0 && (int) $number < 0) || (int) $number < 0 -
PHP_INT_MAX) {
trigger_error(
'convert_number_to_words only accepts numbers between -' .
PHP_INT_MAX . ' and ' . PHP_INT_MAX,
E_USER_WARNING
);
return false;
}
if ($number < 0) {
return $negative . convert_number_to_words(abs($number));
}
$string = $fraction = null;
if (strpos($number, '.') !== false) {
list($number, $fraction) = explode('.', $number);
}
switch (true) {
case $number < 100:
$string = $dictionary[$number];
break;
case $number < 100:
$tens = ((int) ($number / 10)) * 10;
$units = $number % 10;
$string = $dictionary[$tens];
if ($units) {
$string .= $hyphen . $dictionary[$units];
}
break;
case $number < 1000:
$hundreds = $number / 100;
$remainder = $number % 100;
$string = $dictionary[$hundreds] . ' ' . $dictionary[100];
if ($remainder) {
$string .= $conjunction . convert_number_to_words($remainder);
}
break;;
default:
$baseUnit = pow(100000, floor(log($number, 100000)));
$numBaseUnits = (int) ($number / $baseUnit);
$remainder = $number % $baseUnit;
$string = convert_number_to_words($numBaseUnits) . ' ' .
$dictionary[$baseUnit];
if ($remainder) {
$string .= $remainder < 100 ? $conjunction : $separator;
$string .= convert_number_to_words($remainder);
}
break;
}
if (null !== $fraction && is_numeric($fraction)) {
$string .= $decimal;
$words = array();
foreach (str_split((string) $fraction) as $number) {
$words[] = $dictionary[$number];
}
$string .= implode(' ', $words);
}
return $string;
}
?>
Page "numtoword.php"
Page "index.php"
<?php
include('numword.php');
echo convert_number_to_words(287989012375);
?>
It looks like you are making it more difficult than it needs to be. I created a simpler recursive function, moved the dictionary and settings outside the function (generating a dictionary array on every function call was eating up a LOT of memory and is not necessary). I didn't include fractions but this should be a good starting point to expand off of:
<?php
$devnagriNumeralWords = [
'dictionary' => [
'smallUnits' => [
0 => 'शुन्य',
1 => 'एक',
2 => 'दुई',
3 => 'तीन',
4 => 'चार',
5 => 'पाँच',
6 => 'छ',
7 => 'सात',
8 => 'आठ',
9 => 'नौ',
10 => 'दश',
11 => 'एघार',
12 => 'बाह्र',
13 => 'तेह्र',
14 => 'चौध',
15 => 'पन्ध',
16 => 'सोह्र',
17 => 'सत्र',
18 => 'अठार',
19 => 'उन्नाइस',
20 => 'विस',
21 => 'एक्काइस',
22 => 'बाइस',
23 => 'तेइस',
24 => 'चौविस',
25 => 'पच्चिस',
26 => 'छब्बिस',
27 => 'सत्ताइस',
28 => 'अठ्ठाईस',
29 => 'उनन्तिस',
30 => 'तिस',
31 => 'एकत्तिस',
32 => 'बत्तिस',
33 => 'तेत्तिस',
34 => 'चौँतिस ',
35 => 'पैँतिस',
36 => 'छत्तिस',
37 => 'सैँतीस',
38 => 'अठतीस',
39 => 'उनन्चालीस',
40 => 'चालीस',
41 => 'एकचालीस',
42 => 'बयालीस',
43 => 'त्रियालीस',
44 => 'चवालीस',
45 => 'पैँतालीस',
46 => 'छयालीस',
47 => 'सरचालीस',
48 => 'अठचालीस',
49 => 'उनन्चास',
50 => 'पचास',
51 => 'एकाउन्न',
52 => 'बाउन्न',
53 => 'त्रिपन्न',
54 => 'चउन्न',
55 => 'पचपन्न',
56 => 'छपन्न',
57 => 'सन्ताउन्न ',
58 => 'अन्ठाउन्न',
59 => 'उनन्साठी',
60 => 'साठी',
61 => 'एकसट्ठी',
62 => 'बयसट्ठी',
63 => 'त्रिसट्ठी',
64 => 'चौंसट्ठी',
65 => 'पैंसट्ठी',
66 => 'छयसट्ठी',
67 => 'सतसट्ठी',
68 => 'अठसट्ठी',
69 => 'उनन्सत्तरी',
70 => 'सत्तरी',
71 => 'एकहत्तर',
72 => 'बहत्तर',
73 => 'त्रिहत्तर',
74 => 'चौहत्तर',
75 => 'पचहत्तर',
76 => 'छयहत्तर',
77 => 'सतहत्तर',
78 => 'अठहत्तर',
79 => 'उनासी',
80 => 'असी',
81 => 'एकासी',
82 => 'बयासी',
83 => 'त्रियासी',
84 => 'चौरासी',
85 => 'पचासी',
86 => 'छयासी',
87 => 'सतासी',
88 => 'अठासी',
89 => 'उनान्नब्बे',
90 => 'नब्बे',
91 => 'एकान्नब्बे',
92 => 'बयानब्बे',
93 => 'त्रियान्नब्बे',
94 => 'चौरान्नब्बे',
95 => 'पन्चानब्बे',
96 => 'छयान्नब्बे',
97 => 'सन्तान्नब्बे',
98 => 'अन्ठान्नब्बे',
99 => 'उनान्सय'
],
'largeUnits' => [
100 => 'सय',
1000 => 'हजार',
100000 => 'लाख',
10000000 => 'करोड',
1000000000 => 'अर्ब',
100000000000 => 'खर्ब'
]
],
'hyphen' => '-',
'conjunction' => ' ',
'separator' => ' ',
'negative' => 'negative ',
'decimal' => ' point '
];
function convert_devnagri_number_to_words($number) {
global $devnagriNumeralWords;
$numLen = strlen($number);
$output = [ 'prefix' => '', 'base' => '', 'suffix' => '' ];
$base = pow(10, $numLen-1);
$smallestLargeUnit = array_keys($devnagriNumeralWords['dictionary']['largeUnits'])[0];
$isNegative = $number < 0;
if( $isNegative ) {
$output['prefix'] .= $devnagriNumeralWords['negative'];
$number = abs($number);
}
if( $number < $smallestLargeUnit ) {
// Number is less than 100
$prefix = $number;
} else {
// Get base amount (100, 1000, 100000, etc)
if( isset($devnagriNumeralWords['dictionary']['largeUnits'][$base]) ) {
$largeUnit = $devnagriNumeralWords['dictionary']['largeUnits'][$base];
} else {
// No exact large unit match, find next smallest
while( $base >= $smallestLargeUnit ) {
$base = (int) ($base / 10);
if( isset($devnagriNumeralWords['dictionary']['largeUnits'][$base]) ) {
break; // Found a match!
}
}
}
$output['base'] .= $devnagriNumeralWords['dictionary']['largeUnits'][$base];
// Get prefix, e.g. "28" when number is 28564
$prefix = (int) ($number / $base);
// Subtract prefix to get next part to process
// E.g. the next number is 345 when the number is 85345
$nextNumber = $number - ($prefix * $base);
if( $nextNumber > 0 )
$output['suffix'] = convert_devnagri_number_to_words($nextNumber);
}
if( $prefix >= 0 ) {
$output['prefix'] .= $devnagriNumeralWords['dictionary']['smallUnits'][$prefix];
}
// Put it all together!
return implode( $devnagriNumeralWords['separator'], array_filter($output) );
}
echo convert_devnagri_number_to_words(287989012375);

How to insert these element in array

Suppose an array is give:
$given_array=Array(
[0] => 30
[1] => 45
[2] => 60
[3] => 75
[4] => 90
[5] => 105
[6] => 120
[7] => 135)
A number is given example: 195
Number until 195 needs to be inserted with a difference of 15
So resulting array is:
Array(
[0] => 30
[1] => 45
[2] => 60
[3] => 75
[4] => 90
[5] => 105
[6] => 120
[7] => 135
[8] => 150
[9] => 165
[10] => 180
[11] => 195)
Need to know the best approach to do so time required is least.
So far i have tried:
$given_num=195;
if((given_num-$given_array[count($given_array)-1])!=15 && count($given_array)>0){
while(($given_array[count($given_array)-1]+15)<=given_num){
$given_array[]=$given_array[count($given_array)-1]+15;
}
}
Results are correct but not time feasible
I see that the goal is to have an array with subsequent numbers divisible by 15. Unless you really have to reuse the old array (I wouldn't know why), I
would suggest creating a new array with range():
$given_array = range($given_array[0], 195, 15);
Haven't tried yours and not sure whats wrong with it regarding speed but try this.
<?php
$given_array=[30, 45, 60, 75, 90, 105, 120, 135];
$newNumber = 195;
$count = floor(($newNumber - $given_array[count($given_array)-1]) / 15);
for($i=0; $i<$count; $i++) {
array_push($given_array, $given_array[count($given_array)-1]+15);
}
print_r($given_array);
example: https://3v4l.org/vPiAW
I would say:
$given_num = 195;
$last = end($given_array);
while ($given_num > $last) {
$last = min($last + 15, $given_num);
$given_array[] = $last;
}
But the range-version is quite nice =)
Another short solution using end function:
while (($last = end($given_array)) < 195) $given_array[] = $last+15;
// now, $given_array contains all the needed items

C128 Barcode script in php

I want to add code 128 auto barcode in codeigniter framework.I used http://davidscotttufts.com/2009/03/31/how-to-create-barcodes-in-php/ for this but it is generating code128B format.I have also used http://www.barcodephp.com/en/download but could not be able to properly add classes in codeigniter framework.Can anyone help me or suggest me code128 auto barcode php script.
Thanks in advance
<?php
// Get thickness parameter from $_GET:
$thickness = ( isset( $_GET["thickness"] ) ? $_GET[ "thickness" ] : 2 );
$text = (isset($_GET["text"])?$_GET["text"]:"00000000024");
//$text=(int)$text;
$size = (isset($_GET["size"])?$_GET["size"]:"30");
$orientation = (isset($_GET["orientation"])?$_GET["orientation"]:"horizontal");
$code_type = (isset($_GET["codetype"])?$_GET["codetype"]:"code128");
$code_string = "";
// Translate the $text into barcode the correct $code_type
if ( strtolower($code_type) == "code128" ) {
$code_array = array(
0 => '11011001100',
1 => '11001101100',
2 => '11001100110',
3 => '10010011000',
4 => '10010001100',
5 => '10001001100',
6 => '10011001000',
7 => '10011000100',
8 => '10001100100',
9 => '11001001000',
10 => '11001000100',
11 => '11000100100',
12 => '10110011100',
13 => '10011011100',
14 => '10011001110',
15 => '10111001100',
16 => '10011101100',
17 => '10011100110',
18 => '11001110010',
19 => '11001011100',
20 => '11001001110',
21 => '11011100100',
22 => '11001110100',
23 => '11101101110',
24 => '11101001100',
25 => '11100101100',
26 => '11100100110',
27 => '11101100100',
28 => '11100110100',
29 => '11100110010',
30 => '11011011000',
31 => '11011000110',
32 => '11000110110',
33 => '10100011000',
34 => '10001011000',
35 => '10001000110',
36 => '10110001000',
37 => '10001101000',
38 => '10001100010',
39 => '11010001000',
40 => '11000101000',
41 => '11000100010',
42 => '10110111000',
43 => '10110001110',
44 => '10001101110',
45 => '10111011000',
46 => '10111000110',
47 => '10001110110',
48 => '11101110110',
49 => '11010001110',
50 => '11000101110',
51 => '11011101000',
52 => '11011100010',
53 => '11011101110',
54 => '11101011000',
55 => '11101000110',
56 => '11100010110',
57 => '11101101000',
58 => '11101100010',
59 => '11100011010',
60 => '11101111010',
61 => '11001000010',
62 => '11110001010',
63 => '10100110000',
64 => '10100001100',
65 => '10010110000',
66 => '10010000110',
67 => '10000101100',
68 => '10000100110',
69 => '10110010000',
70 => '10110000100',
71 => '10011010000',
72 => '10011000010',
73 => '10000110100',
74 => '10000110010',
75 => '11000010010',
76 => '11001010000',
77 => '11110111010',
78 => '11000010100',
79 => '10001111010',
80 => '10100111100',
81 => '10010111100',
82 => '10010011110',
83 => '10111100100',
84 => '10011110100',
85 => '10011110010',
86 => '11110100100',
87 => '11110010100',
88 => '11110010010',
89 => '11011011110',
90 => '11011110110',
91 => '11110110110',
92 => '10101111000',
93 => '10100011110',
94 => '10001011110',
95 => '10111101000',
96 => '10111100010',
97 => '11110101000',
98 => '11110100010',
99 => '10111011110',
100 => '10111101110',
101 => '11101011110',
102 => '11110101110',
'c' => '10111011110',
'b' => '10111101110',
'a' => '11101011110',
'A' => '11010000100',
'B' => '11010010000',
'C' => '11010011100',
'S' => '1100011101011'
);
$code = array();
$strCode;
// settype($code,'string');
//$this->sourceCode = $code;
$nbKr = strlen($code);
$strCode = '';
for( $i=0; $i<$nbKr; $i++ ) {
$code[$i] = substr($code, $i, 1);
}
$strCode = $code_array['B']; // Start
$checksum = 104 ;
$j = 1 ;
for( $i=0; $i<$nbKr; $i++ ) {
$tmp = ord($code[$i]) - 32 ;
$checksum += ( $j++ * $tmp ) ;
$strCode .= $code_array[$tmp];
}
$checksum %= 103 ;
$strCode .= $code_array[$checksum];
$strCode .= $code_array['S']; // Stop
$strCode = $strCode;
$tmp = strlen($strCode) + 20;
$width = $tmp;
}
// Pad the edges of the barcode
$code_length = 20;
for ( $i=1; $i <= strlen($code_string); $i++ )
$code_length = $code_length + (integer)(substr($code_string,($i-1),1));
if ( strtolower($orientation) == "horizontal" ) {
//$img_width = $code_length;
$img_width = $code_length * $thickness;
$img_height = $size;
} else {
$img_width = $size;
$img_height = $code_length;
}
$image = imagecreate($img_width, $img_height);
$black = imagecolorallocate ($image, 0, 0, 0);
$white = imagecolorallocate ($image, 255, 255, 255);
imagefill( $image, 0, 0, $white );
//$location = 10;
$location = 10 * $thickness;
for ( $position = 1 ; $position <= strlen($code_string); $position++ ) {
//$cur_size = $location + ( substr($code_string, ($position-1), 1);
$cur_size = $location + ( substr($code_string, ($position-1), 1) *$thickness);
if ( strtolower($orientation) == "horizontal" )
imagefilledrectangle( $image, $location, 0, $cur_size, $img_height, ($position % 2 == 0 ? $white : $black) );
else
imagefilledrectangle( $image, 0, $location, $img_width, $cur_size, ($position % 2 == 0 ? $white : $black) );
$location = $cur_size;
}
// Draw barcode to the screen
header ('Content-type: image/png');
imagepng($image);
imagedestroy($image);
?>
You can actually follow the examples at https://github.com/tecnickcom/tc-lib-barcode/blob/develop/example/index.php
For example:
$bobj = $barcode->getBarcodeObj('QRCODE,H', 'hello world', -4, -4, 'black');
echo "<img alt=\"Embedded Image\" src=\"data:image/png;base64,".base64_encode($bobj->getPngData())."\" />";
or if you want to print the barcode in a different format:
echo $bobj->getHtmlDiv();
The examples uses the tc-lib-barcode (https://github.com/tecnickcom/tc-lib-barcode) PHP Software library to generate both linear and bidimensional barcodes.
The source code is fully PSR-2 compliant and can be easily added to your PHP projects using Composer.
The original code has been ported and refactored from TCPDF and already used in billions of documents.

Generating UNIQUE Random Numbers within a range

I need to generate random UNIQUE numbers within a range, how can I do that? I can generate random number by
generator:
$arr = [];
$x = rand($min, $max);
$len = count($arr);
$flag = 0;
for($i = 0; $i < $len; $i++)
{
if ($flag === 1)
goto generator;
if ($x === $arr[$i])
$flag = 1;
}
$arr[$index] = $x;
$index++;
goto generator;
I know this code is bad, so I need a better optimized code of my version !
help !
example:
if i need to generate 3 numbers within 1 to 15 they should be like 5, 9, 1 but not 3,1,2 [with in 1 - 3 (numbers i want to generate) ]
Array with range of numbers at random order:
$numbers = range(1, 20);
shuffle($numbers);
Wrapped function:
function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $quantity);
}
Example:
<?php
print_r( UniqueRandomNumbersWithinRange(0,25,5) );
?>
Result:
Array
(
[0] => 14
[1] => 16
[2] => 17
[3] => 20
[4] => 1
)
$len = 10; // total number of numbers
$min = 100; // minimum
$max = 999; // maximum
$range = []; // initialize array
foreach (range(0, $len - 1) as $i) {
while(in_array($num = mt_rand($min, $max), $range));
$range[] = $num;
}
print_r($range);
I was interested to see how the accepted answer stacks up against mine. It's useful to note, a hybrid of both may be advantageous; in fact a function that conditionally uses one or the other depending on certain values:
# The accepted answer
function randRange1($min, $max, $count)
{
$numbers = range($min, $max);
shuffle($numbers);
return array_slice($numbers, 0, $count);
}
# My answer
function randRange2($min, $max, $count)
{
$i = 0;
$range = array();
while ($i++ < $count) {
while(in_array($num = mt_rand($min, $max), $range));
$range[] = $num;
}
return $range;
}
echo 'randRange1: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange1: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
The results:
randRange1: small range, high count
0.019910097122192
randRange2: small range, high count
1.5043621063232
randRange1: high range, small count
2.4722430706024
randRange2: high range, small count
0.0001051425933837
If you're using a smaller range and a higher count of returned values, the accepted answer is certainly optimal; however as I had expected, larger ranges and smaller counts will take much longer with the accepted answer, as it must store every possible value in range. You even run the risk of blowing PHP's memory cap. A hybrid that evaluates the ratio between range and count, and conditionally chooses the generator would be the best of both worlds.
The idea consists to use the keys, when a value is already present in the array keys, the array size stays the same:
function getDistinctRandomNumbers ($nb, $min, $max) {
if ($max - $min + 1 < $nb)
return false; // or throw an exception
$res = array();
do {
$res[mt_rand($min, $max)] = 1;
} while (count($res) !== $nb);
return array_keys($res);
}
Pro: This way avoids the use of in_array and doesn't generate a huge array. So, it is fast and preserves a lot of memory.
Cons: when the rate (range/quantity) decreases, the speed decreases too (but stays correct). For a same rate, relative speed increases with the range size.(*)
(*) I understand that fact since there are more free integers to select (in particular for the first steps), but if somebody has the mathematical formula that describes this behaviour, I am interested by, don't hesitate.
Conclusion: The best "general" function seems to be a mix between this function and #Anne function that is more efficient with a little rate. This function should switch between the two ways when a certain quantity is needed and a rate (range/quantity) is reached. So the complexity/time of the test to know that, must be taken in account.
If you want to generate 100 numbers that are random, but each number appearing only once, a good way would be to generate an array with the numbers in order, then shuffle it.
Something like this:
$arr = array();
for ($i=1;$i<=101;$i++) {
$arr[] = $i;
}
shuffle($arr);
print_r($arr);
Output will look something like this:
Array
(
[0] => 16
[1] => 93
[2] => 46
[3] => 55
[4] => 18
[5] => 63
[6] => 19
[7] => 91
[8] => 99
[9] => 14
[10] => 45
[11] => 68
[12] => 61
[13] => 86
[14] => 64
[15] => 17
[16] => 27
[17] => 35
[18] => 87
[19] => 10
[20] => 95
[21] => 43
[22] => 51
[23] => 92
[24] => 22
[25] => 58
[26] => 71
[27] => 13
[28] => 66
[29] => 53
[30] => 49
[31] => 78
[32] => 69
[33] => 1
[34] => 42
[35] => 47
[36] => 26
[37] => 76
[38] => 70
[39] => 100
[40] => 57
[41] => 2
[42] => 23
[43] => 15
[44] => 96
[45] => 48
[46] => 29
[47] => 81
[48] => 4
[49] => 33
[50] => 79
[51] => 84
[52] => 80
[53] => 101
[54] => 88
[55] => 90
[56] => 56
[57] => 62
[58] => 65
[59] => 38
[60] => 67
[61] => 74
[62] => 37
[63] => 60
[64] => 21
[65] => 89
[66] => 3
[67] => 32
[68] => 25
[69] => 52
[70] => 50
[71] => 20
[72] => 12
[73] => 7
[74] => 54
[75] => 36
[76] => 28
[77] => 97
[78] => 94
[79] => 41
[80] => 72
[81] => 40
[82] => 83
[83] => 30
[84] => 34
[85] => 39
[86] => 6
[87] => 98
[88] => 8
[89] => 24
[90] => 5
[91] => 11
[92] => 73
[93] => 44
[94] => 85
[95] => 82
[96] => 75
[97] => 31
[98] => 77
[99] => 9
[100] => 59
)
If you need 5 random numbers between 1 and 15, you should do:
var_dump(getRandomNumbers(1, 15, 5));
function getRandomNumbers($min, $max, $count)
{
if ($count > (($max - $min)+1))
{
return false;
}
$values = range($min, $max);
shuffle($values);
return array_slice($values,0, $count);
}
It will return false if you specify a count value larger then the possible range of numbers.
You can try next code:
function unique_randoms($min, $max, $count) {
$arr = array();
while(count($arr) < $count){
$tmp =mt_rand($min,$max);
if(!in_array($tmp, $arr)){
$arr[] = $tmp;
}
}
return $arr;
}
Get a random number. Is it stored in the array already? If not, store it. If so, then go get another random number and repeat.
When creating an application where I needed to generate 30,000 unique numbers within a larger range, I was able to cut down processing time from 25 seconds to 1.5 seconds using this method.
The idea is that PHP is much faster at generating random numbers than it is at checking the existence of items in an array - that is why using a while(in_array) loop can be slow.
$count = 0;
$collectNumbers = [];
while ($count < 30000) {
for ($i = 0; $i < 60000; $i++) {
$rand = mt_rand(1, 100000);
$collectNumbers[] = $rand;
}
$unique = array_unique($collectNumbers);
$count = count($unique);
}
$finalArray = array_slice($unique, 0, 30000);
This will return 30,000 unique numbers extremely quickly. Using an iteration value that is double the amount of numbers you need to generate can increase the likelihood of unique numbers the first iteration... but regardless of how many iterations it takes, this will produce a result faster than checking your array for repeated numbers in a loop.
This probably will solve your problem:
<?php print_r(array_rand(range(1,50), 5)); ?>
I guess this is probably a non issue for most but I tried to solve it. I think I have a pretty decent solution. In case anyone else stumbles upon this issue.
function randomNums($gen, $trim, $low, $high)
{
$results_to_gen = $gen;
$low_range = $low;
$high_range = $high;
$trim_results_to= $trim;
$items = array();
$results = range( 1, $results_to_gen);
$i = 1;
foreach($results as $result)
{
$result = mt_rand( $low_range, $high_range);
$items[] = $result;
}
$unique = array_unique( $items, SORT_NUMERIC);
$countem = count( $unique);
$unique_counted = $countem -$trim_results_to;
$sum = array_slice($unique, $unique_counted);
foreach ($sum as $key)
{
$output = $i++.' : '.$key.'<br>';
echo $output;
}
}
randomNums(1100, 1000 ,890000, 899999);
This is how I would do it.
$randnum1 = mt_rand(1,20);
$nomatch = 0;
while($nomatch == 0){
$randnum2 = mt_rand(1,20);
if($randnum2 != $randnum1){
$nomatch = 1;
}
}
$nomatch = 0;
while($nomatch == 0){
$randnum3 = mt_rand(1,20);
if(($randnum3 != $randnum1)and($randnum3 != $randnum2)){
$nomatch = 1;
}
}
Then you can echo the results to check
echo "Random numbers are " . $randnum1 . "," . $randnum2 . ", and " . $randnum3 . "\n";
The "shuffle" method has a MAJOR FALW. When the numbers are big, shuffle 3 billion indexs will instantly CAUSE 500 error. Here comes a best solution for really big numbers.
function getRandomNumbers($min, $max, $total) {
$temp_arr = array();
while(sizeof($temp_arr) < $total) $temp_arr[rand($min, $max)] = true;
return $temp_arr;
}
Say I want to get 10 unique random numbers from 1 billion to 4 billion.
$random_numbers = getRandomNumbers(1000000000,4000000000,10);
PS: Execution time: 0.027 microseconds
Simply use this function and pass the count of number you want to generate
Code:
function randomFix($length)
{
$random= "";
srand((double)microtime()*1000000);
$data = "AbcDE123IJKLMN67QRSTUVWXYZ";
$data .= "aBCdefghijklmn123opq45rs67tuv89wxyz";
$data .= "0FGH45OP89";
for($i = 0; $i < $length; $i++)
{
$random .= substr($data, (rand()%(strlen($data))), 1);
}
return $random;}
The best way to generate the unique random number is
<?php
echo md5(uniqid(mt_rand(), true).microtime(true));
?>

Find missing numbers in array

I'm trying to find each missing number in an array like the following.
Array (
[0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8
[8] => 9 [9] => 10 [10] => 11 [11] => 12 [12] => 13 [13] => 14 [14] => 15
[15] => 16 [16] => 17 [17] => 18 [18] => 19 [19] => 20 [20] => 21 [21] => 22
[22] => 23 [23] => 24 [24] => 25 [25] => 26 [26] => 27 [27] => 28 [28] => 29
[29] => 30 [30] => 31 [31] => 32 [32] => 33 [33] => 34 [34] => 35 [35] => 36
[36] => 37 [37] => 38 [38] => 39 [39] => 40 [40] => 41 [41] => 42 [42] => 43
[43] => 44 [44] => 45 [45] => 46 [46] => 47 [47] => 48 [48] => 49 [49] => 50
[50] => 51 [51] => 52 [52] => 53 [53] => 54 [54] => 55 [55] => 56 [56] => 57
[57] => 58 [58] => 59 [59] => 60 [60] => 61 [61] => 62 [62] => 63 [63] => 64
[64] => 67 [65] => 68 [66] => 69
)
The numbers 65,66 are missing in this particular array.
My question how do I figure out which numbers are missing with the help of PHP. Specifically what I need to find out is the lowest missing number.
Why: Because then I can assign that number to a member as an id.
You can make use of array_diff and range functions as:
// given array. 3 and 6 are missing.
$arr1 = array(1,2,4,5,7);
// construct a new array:1,2....max(given array).
$arr2 = range(1,max($arr1));
// use array_diff to get the missing elements
$missing = array_diff($arr2,$arr1); // (3,6)
I'm assuming the number is the element, not the key, of the array. I'm also assuming that the numbers start from 1, not 0.
$Expected = 1;
foreach ($InputArray as $Key => $Number)
{
if ($Expected != $Number)
{
break;
}
$Expected++;
}
echo $Number;
For big sorted arrays of unique numbers, you can binary search the array for either the lowest or highest unused number. Cost=Log2N. Example: 65536 items can be searched in 16 loops since
if ( arr[hi] - arr[lo] > hi - lo )
... there are unused numbers in that range ...
So (I don't know PHP, but it can be translated...):
lo = first entry index
hi = last entry index
if ( arr[hi] - arr[lo] == hi - lo )
return arr[hi]+1; // no gaps so return highest + 1
do
{
mid = (lo + hi) / 2;
if ( arr[mid] - arr[lo] > mid - lo ) // there is a gap in the bottom half somewhere
hi = mid; // search the bottom half
else
lo = mid; // search the top half
} while ( hi > lo + 1 ); // search until 2 left
return arr[lo]+1;
If given input is not in sorted order and size of input is very large then we can use following logic in any programming language:
Algorithm
bring smaller chunk into memory from large input
initialize three variables say min = 0, max = 0 and missingIds = []
scan smaller chunked input from left to right
if scannedValue found in missingIds
then,
pop scannedValue from missingIds
go to next value;
If scanned value is near to min
then,
find all the missing numbers between scannedValue and min, push into missingIds
min = scannedValue;
Else if scanned value is near to max
then,
find all the missing numbers between scannedValue and max, push into missingIds
max = scannedValue;
repeat above steps until large input scanned from left to right
Example in PHP
<?php
$largeInput = [40,41,42,43,44,45,1,2,3,4,5,6,7,8,9,10,11,12,13,14,35,36,37,38,39,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,67,68,69,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34];
$missingIds = [];
$min = 0;
$max = 0;
$chunkSize = 10;
$chunkNo = 0;
$currentInput = array_slice($largeInput, $chunkNo, $chunkSize);
while(count($currentInput) > 0) {
foreach($currentInput as $id) {
if(in_array($id,$missingIds)) {
$missingIds = array_diff($missingIds,[$id]);
continue;
}
if($id <= $min) {
$distMin = $min - $id;
if($distMin > 2) {
$tempArr = range($id+1,$min-1);
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
} else if ($distMin > 1) {
$tempArr = [$id+1];
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
}
$min = $id;
} else if ($id >= $max){
$distMax = $id - $max;
if($distMax > 2) {
$tempArr = range($max+1,$id-1);
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
} else if ($distMax > 1) {
$tempArr = [$max+1];
$missingIds = array_merge($missingIds, $tempArr);
$tempArr = [];
}
$max = $id;
}
}
$chunkNo++;
$currentInput = array_slice($largeInput, $chunkNo, $chunkSize);
}
print_r($missingIds);
//$idArrayMissing = array([0] => 1, [1] => 2, [2] => 4, [3] => 5, [4] => 6, [5] => 7);
$idArrayMissing = array(1, 2, 4, 5, 6, 7);
//$idArrayFull = array([0] => 1, [1] => 2, [2] => 3, [3] => 4, [4] => 5, [5] => 6);
$idArrayFull = array(1, 2, 3, 4, 5, 6);
function gap($arr)
{
while (list($k, $v) = each($arr))
if ($k != ($v-1))
return $k;
return -1;
}
print "ok:" . gap($idArrayMissing) . "<br/>\n";
print "full:" . gap($idArrayFull) . "<br/>\n";
The return of the gap function can be 2 values:
-1 could indicate that the array has been traversed and there are no free slots or
$k+1 which could indicate that the first free slot is on the end of the array.
It can also be done easily by using in_array() function like this:
// lets say $InputArray has all the data
// lets declare a variable which we will search inside the $InputArray array and lets initialize it with either 0 or 1 or with the minimum value found inside $InputArray
$start_counting = 1;
$max_value = count($InputArray);
if (!(in_array($start_counting, $InputArray)))
{
echo "Value: ".$start_counting." is missing!"."<br>" ;
}
else{
if($start_counting <= $max_value -1)
{$start_counting++;}
}
else if($start_counting > $max_value -1)
{
echo "All missing numbers printed!"
}
}

Categories