PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.7
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.7
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Calculation / Engineering.php

Engineering.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.10.7, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering.php

2,808 lines 99.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5 use Complex\Complex;
6 use Complex\Exception as ComplexException;
7
8 class Engineering
9 {
10 /**
11 * EULER.
12 */
13 const EULER = 2.71828182845904523536;
14
15 /**
16 * Details of the Units of measure that can be used in CONVERTUOM().
17 *
18 * @var mixed[]
19 */
20 private static $conversionUnits = [
21 'g' => ['Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => true],
22 'sg' => ['Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => false],
23 'lbm' => ['Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false],
24 'u' => ['Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true],
25 'ozm' => ['Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false],
26 'm' => ['Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => true],
27 'mi' => ['Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => false],
28 'Nmi' => ['Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false],
29 'in' => ['Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => false],
30 'ft' => ['Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => false],
31 'yd' => ['Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => false],
32 'ang' => ['Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => true],
33 'Pica' => ['Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false],
34 'yr' => ['Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => false],
35 'day' => ['Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => false],
36 'hr' => ['Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => false],
37 'mn' => ['Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => false],
38 'sec' => ['Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => true],
39 'Pa' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true],
40 'p' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true],
41 'atm' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true],
42 'at' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true],
43 'mmHg' => ['Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true],
44 'N' => ['Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => true],
45 'dyn' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true],
46 'dy' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true],
47 'lbf' => ['Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => false],
48 'J' => ['Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => true],
49 'e' => ['Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => true],
50 'c' => ['Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true],
51 'cal' => ['Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => true],
52 'eV' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true],
53 'ev' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true],
54 'HPh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false],
55 'hh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false],
56 'Wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true],
57 'wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true],
58 'flb' => ['Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false],
59 'BTU' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false],
60 'btu' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false],
61 'HP' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false],
62 'h' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false],
63 'W' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true],
64 'w' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true],
65 'T' => ['Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => true],
66 'ga' => ['Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => true],
67 'C' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false],
68 'cel' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false],
69 'F' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false],
70 'fah' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false],
71 'K' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false],
72 'kel' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false],
73 'tsp' => ['Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false],
74 'tbs' => ['Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false],
75 'oz' => ['Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false],
76 'cup' => ['Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => false],
77 'pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false],
78 'us_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false],
79 'uk_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false],
80 'qt' => ['Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => false],
81 'gal' => ['Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => false],
82 'l' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true],
83 'lt' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true],
84 ];
85
86 /**
87 * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
88 *
89 * @var mixed[]
90 */
91 private static $conversionMultipliers = [
92 'Y' => ['multiplier' => 1E24, 'name' => 'yotta'],
93 'Z' => ['multiplier' => 1E21, 'name' => 'zetta'],
94 'E' => ['multiplier' => 1E18, 'name' => 'exa'],
95 'P' => ['multiplier' => 1E15, 'name' => 'peta'],
96 'T' => ['multiplier' => 1E12, 'name' => 'tera'],
97 'G' => ['multiplier' => 1E9, 'name' => 'giga'],
98 'M' => ['multiplier' => 1E6, 'name' => 'mega'],
99 'k' => ['multiplier' => 1E3, 'name' => 'kilo'],
100 'h' => ['multiplier' => 1E2, 'name' => 'hecto'],
101 'e' => ['multiplier' => 1E1, 'name' => 'deka'],
102 'd' => ['multiplier' => 1E-1, 'name' => 'deci'],
103 'c' => ['multiplier' => 1E-2, 'name' => 'centi'],
104 'm' => ['multiplier' => 1E-3, 'name' => 'milli'],
105 'u' => ['multiplier' => 1E-6, 'name' => 'micro'],
106 'n' => ['multiplier' => 1E-9, 'name' => 'nano'],
107 'p' => ['multiplier' => 1E-12, 'name' => 'pico'],
108 'f' => ['multiplier' => 1E-15, 'name' => 'femto'],
109 'a' => ['multiplier' => 1E-18, 'name' => 'atto'],
110 'z' => ['multiplier' => 1E-21, 'name' => 'zepto'],
111 'y' => ['multiplier' => 1E-24, 'name' => 'yocto'],
112 ];
113
114 /**
115 * Details of the Units of measure conversion factors, organised by group.
116 *
117 * @var mixed[]
118 */
119 private static $unitConversions = [
120 'Mass' => [
121 'g' => [
122 'g' => 1.0,
123 'sg' => 6.85220500053478E-05,
124 'lbm' => 2.20462291469134E-03,
125 'u' => 6.02217000000000E+23,
126 'ozm' => 3.52739718003627E-02,
127 ],
128 'sg' => [
129 'g' => 1.45938424189287E+04,
130 'sg' => 1.0,
131 'lbm' => 3.21739194101647E+01,
132 'u' => 8.78866000000000E+27,
133 'ozm' => 5.14782785944229E+02,
134 ],
135 'lbm' => [
136 'g' => 4.5359230974881148E+02,
137 'sg' => 3.10810749306493E-02,
138 'lbm' => 1.0,
139 'u' => 2.73161000000000E+26,
140 'ozm' => 1.60000023429410E+01,
141 ],
142 'u' => [
143 'g' => 1.66053100460465E-24,
144 'sg' => 1.13782988532950E-28,
145 'lbm' => 3.66084470330684E-27,
146 'u' => 1.0,
147 'ozm' => 5.85735238300524E-26,
148 ],
149 'ozm' => [
150 'g' => 2.83495152079732E+01,
151 'sg' => 1.94256689870811E-03,
152 'lbm' => 6.24999908478882E-02,
153 'u' => 1.70725600000000E+25,
154 'ozm' => 1.0,
155 ],
156 ],
157 'Distance' => [
158 'm' => [
159 'm' => 1.0,
160 'mi' => 6.21371192237334E-04,
161 'Nmi' => 5.39956803455724E-04,
162 'in' => 3.93700787401575E+01,
163 'ft' => 3.28083989501312E+00,
164 'yd' => 1.09361329797891E+00,
165 'ang' => 1.00000000000000E+10,
166 'Pica' => 2.83464566929116E+03,
167 ],
168 'mi' => [
169 'm' => 1.60934400000000E+03,
170 'mi' => 1.0,
171 'Nmi' => 8.68976241900648E-01,
172 'in' => 6.33600000000000E+04,
173 'ft' => 5.28000000000000E+03,
174 'yd' => 1.76000000000000E+03,
175 'ang' => 1.60934400000000E+13,
176 'Pica' => 4.56191999999971E+06,
177 ],
178 'Nmi' => [
179 'm' => 1.85200000000000E+03,
180 'mi' => 1.15077944802354E+00,
181 'Nmi' => 1.0,
182 'in' => 7.29133858267717E+04,
183 'ft' => 6.07611548556430E+03,
184 'yd' => 2.02537182785694E+03,
185 'ang' => 1.85200000000000E+13,
186 'Pica' => 5.24976377952723E+06,
187 ],
188 'in' => [
189 'm' => 2.54000000000000E-02,
190 'mi' => 1.57828282828283E-05,
191 'Nmi' => 1.37149028077754E-05,
192 'in' => 1.0,
193 'ft' => 8.33333333333333E-02,
194 'yd' => 2.77777777686643E-02,
195 'ang' => 2.54000000000000E+08,
196 'Pica' => 7.19999999999955E+01,
197 ],
198 'ft' => [
199 'm' => 3.04800000000000E-01,
200 'mi' => 1.89393939393939E-04,
201 'Nmi' => 1.64578833693305E-04,
202 'in' => 1.20000000000000E+01,
203 'ft' => 1.0,
204 'yd' => 3.33333333223972E-01,
205 'ang' => 3.04800000000000E+09,
206 'Pica' => 8.63999999999946E+02,
207 ],
208 'yd' => [
209 'm' => 9.14400000300000E-01,
210 'mi' => 5.68181818368230E-04,
211 'Nmi' => 4.93736501241901E-04,
212 'in' => 3.60000000118110E+01,
213 'ft' => 3.00000000000000E+00,
214 'yd' => 1.0,
215 'ang' => 9.14400000300000E+09,
216 'Pica' => 2.59200000085023E+03,
217 ],
218 'ang' => [
219 'm' => 1.00000000000000E-10,
220 'mi' => 6.21371192237334E-14,
221 'Nmi' => 5.39956803455724E-14,
222 'in' => 3.93700787401575E-09,
223 'ft' => 3.28083989501312E-10,
224 'yd' => 1.09361329797891E-10,
225 'ang' => 1.0,
226 'Pica' => 2.83464566929116E-07,
227 ],
228 'Pica' => [
229 'm' => 3.52777777777800E-04,
230 'mi' => 2.19205948372629E-07,
231 'Nmi' => 1.90484761219114E-07,
232 'in' => 1.38888888888898E-02,
233 'ft' => 1.15740740740748E-03,
234 'yd' => 3.85802469009251E-04,
235 'ang' => 3.52777777777800E+06,
236 'Pica' => 1.0,
237 ],
238 ],
239 'Time' => [
240 'yr' => [
241 'yr' => 1.0,
242 'day' => 365.25,
243 'hr' => 8766.0,
244 'mn' => 525960.0,
245 'sec' => 31557600.0,
246 ],
247 'day' => [
248 'yr' => 2.73785078713210E-03,
249 'day' => 1.0,
250 'hr' => 24.0,
251 'mn' => 1440.0,
252 'sec' => 86400.0,
253 ],
254 'hr' => [
255 'yr' => 1.14077116130504E-04,
256 'day' => 4.16666666666667E-02,
257 'hr' => 1.0,
258 'mn' => 60.0,
259 'sec' => 3600.0,
260 ],
261 'mn' => [
262 'yr' => 1.90128526884174E-06,
263 'day' => 6.94444444444444E-04,
264 'hr' => 1.66666666666667E-02,
265 'mn' => 1.0,
266 'sec' => 60.0,
267 ],
268 'sec' => [
269 'yr' => 3.16880878140289E-08,
270 'day' => 1.15740740740741E-05,
271 'hr' => 2.77777777777778E-04,
272 'mn' => 1.66666666666667E-02,
273 'sec' => 1.0,
274 ],
275 ],
276 'Pressure' => [
277 'Pa' => [
278 'Pa' => 1.0,
279 'p' => 1.0,
280 'atm' => 9.86923299998193E-06,
281 'at' => 9.86923299998193E-06,
282 'mmHg' => 7.50061707998627E-03,
283 ],
284 'p' => [
285 'Pa' => 1.0,
286 'p' => 1.0,
287 'atm' => 9.86923299998193E-06,
288 'at' => 9.86923299998193E-06,
289 'mmHg' => 7.50061707998627E-03,
290 ],
291 'atm' => [
292 'Pa' => 1.01324996583000E+05,
293 'p' => 1.01324996583000E+05,
294 'atm' => 1.0,
295 'at' => 1.0,
296 'mmHg' => 760.0,
297 ],
298 'at' => [
299 'Pa' => 1.01324996583000E+05,
300 'p' => 1.01324996583000E+05,
301 'atm' => 1.0,
302 'at' => 1.0,
303 'mmHg' => 760.0,
304 ],
305 'mmHg' => [
306 'Pa' => 1.33322363925000E+02,
307 'p' => 1.33322363925000E+02,
308 'atm' => 1.31578947368421E-03,
309 'at' => 1.31578947368421E-03,
310 'mmHg' => 1.0,
311 ],
312 ],
313 'Force' => [
314 'N' => [
315 'N' => 1.0,
316 'dyn' => 1.0E+5,
317 'dy' => 1.0E+5,
318 'lbf' => 2.24808923655339E-01,
319 ],
320 'dyn' => [
321 'N' => 1.0E-5,
322 'dyn' => 1.0,
323 'dy' => 1.0,
324 'lbf' => 2.24808923655339E-06,
325 ],
326 'dy' => [
327 'N' => 1.0E-5,
328 'dyn' => 1.0,
329 'dy' => 1.0,
330 'lbf' => 2.24808923655339E-06,
331 ],
332 'lbf' => [
333 'N' => 4.448222,
334 'dyn' => 4.448222E+5,
335 'dy' => 4.448222E+5,
336 'lbf' => 1.0,
337 ],
338 ],
339 'Energy' => [
340 'J' => [
341 'J' => 1.0,
342 'e' => 9.99999519343231E+06,
343 'c' => 2.39006249473467E-01,
344 'cal' => 2.38846190642017E-01,
345 'eV' => 6.24145700000000E+18,
346 'ev' => 6.24145700000000E+18,
347 'HPh' => 3.72506430801000E-07,
348 'hh' => 3.72506430801000E-07,
349 'Wh' => 2.77777916238711E-04,
350 'wh' => 2.77777916238711E-04,
351 'flb' => 2.37304222192651E+01,
352 'BTU' => 9.47815067349015E-04,
353 'btu' => 9.47815067349015E-04,
354 ],
355 'e' => [
356 'J' => 1.00000048065700E-07,
357 'e' => 1.0,
358 'c' => 2.39006364353494E-08,
359 'cal' => 2.38846305445111E-08,
360 'eV' => 6.24146000000000E+11,
361 'ev' => 6.24146000000000E+11,
362 'HPh' => 3.72506609848824E-14,
363 'hh' => 3.72506609848824E-14,
364 'Wh' => 2.77778049754611E-11,
365 'wh' => 2.77778049754611E-11,
366 'flb' => 2.37304336254586E-06,
367 'BTU' => 9.47815522922962E-11,
368 'btu' => 9.47815522922962E-11,
369 ],
370 'c' => [
371 'J' => 4.18399101363672E+00,
372 'e' => 4.18398900257312E+07,
373 'c' => 1.0,
374 'cal' => 9.99330315287563E-01,
375 'eV' => 2.61142000000000E+19,
376 'ev' => 2.61142000000000E+19,
377 'HPh' => 1.55856355899327E-06,
378 'hh' => 1.55856355899327E-06,
379 'Wh' => 1.16222030532950E-03,
380 'wh' => 1.16222030532950E-03,
381 'flb' => 9.92878733152102E+01,
382 'BTU' => 3.96564972437776E-03,
383 'btu' => 3.96564972437776E-03,
384 ],
385 'cal' => [
386 'J' => 4.18679484613929E+00,
387 'e' => 4.18679283372801E+07,
388 'c' => 1.00067013349059E+00,
389 'cal' => 1.0,
390 'eV' => 2.61317000000000E+19,
391 'ev' => 2.61317000000000E+19,
392 'HPh' => 1.55960800463137E-06,
393 'hh' => 1.55960800463137E-06,
394 'Wh' => 1.16299914807955E-03,
395 'wh' => 1.16299914807955E-03,
396 'flb' => 9.93544094443283E+01,
397 'BTU' => 3.96830723907002E-03,
398 'btu' => 3.96830723907002E-03,
399 ],
400 'eV' => [
401 'J' => 1.60219000146921E-19,
402 'e' => 1.60218923136574E-12,
403 'c' => 3.82933423195043E-20,
404 'cal' => 3.82676978535648E-20,
405 'eV' => 1.0,
406 'ev' => 1.0,
407 'HPh' => 5.96826078912344E-26,
408 'hh' => 5.96826078912344E-26,
409 'Wh' => 4.45053000026614E-23,
410 'wh' => 4.45053000026614E-23,
411 'flb' => 3.80206452103492E-18,
412 'BTU' => 1.51857982414846E-22,
413 'btu' => 1.51857982414846E-22,
414 ],
415 'ev' => [
416 'J' => 1.60219000146921E-19,
417 'e' => 1.60218923136574E-12,
418 'c' => 3.82933423195043E-20,
419 'cal' => 3.82676978535648E-20,
420 'eV' => 1.0,
421 'ev' => 1.0,
422 'HPh' => 5.96826078912344E-26,
423 'hh' => 5.96826078912344E-26,
424 'Wh' => 4.45053000026614E-23,
425 'wh' => 4.45053000026614E-23,
426 'flb' => 3.80206452103492E-18,
427 'BTU' => 1.51857982414846E-22,
428 'btu' => 1.51857982414846E-22,
429 ],
430 'HPh' => [
431 'J' => 2.68451741316170E+06,
432 'e' => 2.68451612283024E+13,
433 'c' => 6.41616438565991E+05,
434 'cal' => 6.41186757845835E+05,
435 'eV' => 1.67553000000000E+25,
436 'ev' => 1.67553000000000E+25,
437 'HPh' => 1.0,
438 'hh' => 1.0,
439 'Wh' => 7.45699653134593E+02,
440 'wh' => 7.45699653134593E+02,
441 'flb' => 6.37047316692964E+07,
442 'BTU' => 2.54442605275546E+03,
443 'btu' => 2.54442605275546E+03,
444 ],
445 'hh' => [
446 'J' => 2.68451741316170E+06,
447 'e' => 2.68451612283024E+13,
448 'c' => 6.41616438565991E+05,
449 'cal' => 6.41186757845835E+05,
450 'eV' => 1.67553000000000E+25,
451 'ev' => 1.67553000000000E+25,
452 'HPh' => 1.0,
453 'hh' => 1.0,
454 'Wh' => 7.45699653134593E+02,
455 'wh' => 7.45699653134593E+02,
456 'flb' => 6.37047316692964E+07,
457 'BTU' => 2.54442605275546E+03,
458 'btu' => 2.54442605275546E+03,
459 ],
460 'Wh' => [
461 'J' => 3.59999820554720E+03,
462 'e' => 3.59999647518369E+10,
463 'c' => 8.60422069219046E+02,
464 'cal' => 8.59845857713046E+02,
465 'eV' => 2.24692340000000E+22,
466 'ev' => 2.24692340000000E+22,
467 'HPh' => 1.34102248243839E-03,
468 'hh' => 1.34102248243839E-03,
469 'Wh' => 1.0,
470 'wh' => 1.0,
471 'flb' => 8.54294774062316E+04,
472 'BTU' => 3.41213254164705E+00,
473 'btu' => 3.41213254164705E+00,
474 ],
475 'wh' => [
476 'J' => 3.59999820554720E+03,
477 'e' => 3.59999647518369E+10,
478 'c' => 8.60422069219046E+02,
479 'cal' => 8.59845857713046E+02,
480 'eV' => 2.24692340000000E+22,
481 'ev' => 2.24692340000000E+22,
482 'HPh' => 1.34102248243839E-03,
483 'hh' => 1.34102248243839E-03,
484 'Wh' => 1.0,
485 'wh' => 1.0,
486 'flb' => 8.54294774062316E+04,
487 'BTU' => 3.41213254164705E+00,
488 'btu' => 3.41213254164705E+00,
489 ],
490 'flb' => [
491 'J' => 4.21400003236424E-02,
492 'e' => 4.21399800687660E+05,
493 'c' => 1.00717234301644E-02,
494 'cal' => 1.00649785509554E-02,
495 'eV' => 2.63015000000000E+17,
496 'ev' => 2.63015000000000E+17,
497 'HPh' => 1.56974211145130E-08,
498 'hh' => 1.56974211145130E-08,
499 'Wh' => 1.17055614802000E-05,
500 'wh' => 1.17055614802000E-05,
501 'flb' => 1.0,
502 'BTU' => 3.99409272448406E-05,
503 'btu' => 3.99409272448406E-05,
504 ],
505 'BTU' => [
506 'J' => 1.05505813786749E+03,
507 'e' => 1.05505763074665E+10,
508 'c' => 2.52165488508168E+02,
509 'cal' => 2.51996617135510E+02,
510 'eV' => 6.58510000000000E+21,
511 'ev' => 6.58510000000000E+21,
512 'HPh' => 3.93015941224568E-04,
513 'hh' => 3.93015941224568E-04,
514 'Wh' => 2.93071851047526E-01,
515 'wh' => 2.93071851047526E-01,
516 'flb' => 2.50369750774671E+04,
517 'BTU' => 1.0,
518 'btu' => 1.0,
519 ],
520 'btu' => [
521 'J' => 1.05505813786749E+03,
522 'e' => 1.05505763074665E+10,
523 'c' => 2.52165488508168E+02,
524 'cal' => 2.51996617135510E+02,
525 'eV' => 6.58510000000000E+21,
526 'ev' => 6.58510000000000E+21,
527 'HPh' => 3.93015941224568E-04,
528 'hh' => 3.93015941224568E-04,
529 'Wh' => 2.93071851047526E-01,
530 'wh' => 2.93071851047526E-01,
531 'flb' => 2.50369750774671E+04,
532 'BTU' => 1.0,
533 'btu' => 1.0,
534 ],
535 ],
536 'Power' => [
537 'HP' => [
538 'HP' => 1.0,
539 'h' => 1.0,
540 'W' => 7.45701000000000E+02,
541 'w' => 7.45701000000000E+02,
542 ],
543 'h' => [
544 'HP' => 1.0,
545 'h' => 1.0,
546 'W' => 7.45701000000000E+02,
547 'w' => 7.45701000000000E+02,
548 ],
549 'W' => [
550 'HP' => 1.34102006031908E-03,
551 'h' => 1.34102006031908E-03,
552 'W' => 1.0,
553 'w' => 1.0,
554 ],
555 'w' => [
556 'HP' => 1.34102006031908E-03,
557 'h' => 1.34102006031908E-03,
558 'W' => 1.0,
559 'w' => 1.0,
560 ],
561 ],
562 'Magnetism' => [
563 'T' => [
564 'T' => 1.0,
565 'ga' => 10000.0,
566 ],
567 'ga' => [
568 'T' => 0.0001,
569 'ga' => 1.0,
570 ],
571 ],
572 'Liquid' => [
573 'tsp' => [
574 'tsp' => 1.0,
575 'tbs' => 3.33333333333333E-01,
576 'oz' => 1.66666666666667E-01,
577 'cup' => 2.08333333333333E-02,
578 'pt' => 1.04166666666667E-02,
579 'us_pt' => 1.04166666666667E-02,
580 'uk_pt' => 8.67558516821960E-03,
581 'qt' => 5.20833333333333E-03,
582 'gal' => 1.30208333333333E-03,
583 'l' => 4.92999408400710E-03,
584 'lt' => 4.92999408400710E-03,
585 ],
586 'tbs' => [
587 'tsp' => 3.00000000000000E+00,
588 'tbs' => 1.0,
589 'oz' => 5.00000000000000E-01,
590 'cup' => 6.25000000000000E-02,
591 'pt' => 3.12500000000000E-02,
592 'us_pt' => 3.12500000000000E-02,
593 'uk_pt' => 2.60267555046588E-02,
594 'qt' => 1.56250000000000E-02,
595 'gal' => 3.90625000000000E-03,
596 'l' => 1.47899822520213E-02,
597 'lt' => 1.47899822520213E-02,
598 ],
599 'oz' => [
600 'tsp' => 6.00000000000000E+00,
601 'tbs' => 2.00000000000000E+00,
602 'oz' => 1.0,
603 'cup' => 1.25000000000000E-01,
604 'pt' => 6.25000000000000E-02,
605 'us_pt' => 6.25000000000000E-02,
606 'uk_pt' => 5.20535110093176E-02,
607 'qt' => 3.12500000000000E-02,
608 'gal' => 7.81250000000000E-03,
609 'l' => 2.95799645040426E-02,
610 'lt' => 2.95799645040426E-02,
611 ],
612 'cup' => [
613 'tsp' => 4.80000000000000E+01,
614 'tbs' => 1.60000000000000E+01,
615 'oz' => 8.00000000000000E+00,
616 'cup' => 1.0,
617 'pt' => 5.00000000000000E-01,
618 'us_pt' => 5.00000000000000E-01,
619 'uk_pt' => 4.16428088074541E-01,
620 'qt' => 2.50000000000000E-01,
621 'gal' => 6.25000000000000E-02,
622 'l' => 2.36639716032341E-01,
623 'lt' => 2.36639716032341E-01,
624 ],
625 'pt' => [
626 'tsp' => 9.60000000000000E+01,
627 'tbs' => 3.20000000000000E+01,
628 'oz' => 1.60000000000000E+01,
629 'cup' => 2.00000000000000E+00,
630 'pt' => 1.0,
631 'us_pt' => 1.0,
632 'uk_pt' => 8.32856176149081E-01,
633 'qt' => 5.00000000000000E-01,
634 'gal' => 1.25000000000000E-01,
635 'l' => 4.73279432064682E-01,
636 'lt' => 4.73279432064682E-01,
637 ],
638 'us_pt' => [
639 'tsp' => 9.60000000000000E+01,
640 'tbs' => 3.20000000000000E+01,
641 'oz' => 1.60000000000000E+01,
642 'cup' => 2.00000000000000E+00,
643 'pt' => 1.0,
644 'us_pt' => 1.0,
645 'uk_pt' => 8.32856176149081E-01,
646 'qt' => 5.00000000000000E-01,
647 'gal' => 1.25000000000000E-01,
648 'l' => 4.73279432064682E-01,
649 'lt' => 4.73279432064682E-01,
650 ],
651 'uk_pt' => [
652 'tsp' => 1.15266000000000E+02,
653 'tbs' => 3.84220000000000E+01,
654 'oz' => 1.92110000000000E+01,
655 'cup' => 2.40137500000000E+00,
656 'pt' => 1.20068750000000E+00,
657 'us_pt' => 1.20068750000000E+00,
658 'uk_pt' => 1.0,
659 'qt' => 6.00343750000000E-01,
660 'gal' => 1.50085937500000E-01,
661 'l' => 5.68260698087162E-01,
662 'lt' => 5.68260698087162E-01,
663 ],
664 'qt' => [
665 'tsp' => 1.92000000000000E+02,
666 'tbs' => 6.40000000000000E+01,
667 'oz' => 3.20000000000000E+01,
668 'cup' => 4.00000000000000E+00,
669 'pt' => 2.00000000000000E+00,
670 'us_pt' => 2.00000000000000E+00,
671 'uk_pt' => 1.66571235229816E+00,
672 'qt' => 1.0,
673 'gal' => 2.50000000000000E-01,
674 'l' => 9.46558864129363E-01,
675 'lt' => 9.46558864129363E-01,
676 ],
677 'gal' => [
678 'tsp' => 7.68000000000000E+02,
679 'tbs' => 2.56000000000000E+02,
680 'oz' => 1.28000000000000E+02,
681 'cup' => 1.60000000000000E+01,
682 'pt' => 8.00000000000000E+00,
683 'us_pt' => 8.00000000000000E+00,
684 'uk_pt' => 6.66284940919265E+00,
685 'qt' => 4.00000000000000E+00,
686 'gal' => 1.0,
687 'l' => 3.78623545651745E+00,
688 'lt' => 3.78623545651745E+00,
689 ],
690 'l' => [
691 'tsp' => 2.02840000000000E+02,
692 'tbs' => 6.76133333333333E+01,
693 'oz' => 3.38066666666667E+01,
694 'cup' => 4.22583333333333E+00,
695 'pt' => 2.11291666666667E+00,
696 'us_pt' => 2.11291666666667E+00,
697 'uk_pt' => 1.75975569552166E+00,
698 'qt' => 1.05645833333333E+00,
699 'gal' => 2.64114583333333E-01,
700 'l' => 1.0,
701 'lt' => 1.0,
702 ],
703 'lt' => [
704 'tsp' => 2.02840000000000E+02,
705 'tbs' => 6.76133333333333E+01,
706 'oz' => 3.38066666666667E+01,
707 'cup' => 4.22583333333333E+00,
708 'pt' => 2.11291666666667E+00,
709 'us_pt' => 2.11291666666667E+00,
710 'uk_pt' => 1.75975569552166E+00,
711 'qt' => 1.05645833333333E+00,
712 'gal' => 2.64114583333333E-01,
713 'l' => 1.0,
714 'lt' => 1.0,
715 ],
716 ],
717 ];
718
719 /**
720 * parseComplex.
721 *
722 * Parses a complex number into its real and imaginary parts, and an I or J suffix
723 *
724 * @deprecated 2.0.0 No longer used by internal code. Please use the Complex\Complex class instead
725 *
726 * @param string $complexNumber The complex number
727 *
728 * @return mixed[] Indexed on "real", "imaginary" and "suffix"
729 */
730 public static function parseComplex($complexNumber)
731 {
732 $complex = new Complex($complexNumber);
733
734 return [
735 'real' => $complex->getReal(),
736 'imaginary' => $complex->getImaginary(),
737 'suffix' => $complex->getSuffix(),
738 ];
739 }
740
741 /**
742 * Formats a number base string value with leading zeroes.
743 *
744 * @param string $xVal The "number" to pad
745 * @param int $places The length that we want to pad this value
746 *
747 * @return string The padded "number"
748 */
749 private static function nbrConversionFormat($xVal, $places)
750 {
751 if ($places !== null) {
752 if (is_numeric($places)) {
753 $places = (int) $places;
754 } else {
755 return Functions::VALUE();
756 }
757 if ($places < 0) {
758 return Functions::NAN();
759 }
760 if (strlen($xVal) <= $places) {
761 return substr(str_pad($xVal, $places, '0', STR_PAD_LEFT), -10);
762 }
763
764 return Functions::NAN();
765 }
766
767 return substr($xVal, -10);
768 }
769
770 /**
771 * BESSELI.
772 *
773 * Returns the modified Bessel function In(x), which is equivalent to the Bessel function evaluated
774 * for purely imaginary arguments
775 *
776 * Excel Function:
777 * BESSELI(x,ord)
778 *
779 * @category Engineering Functions
780 *
781 * @param float $x The value at which to evaluate the function.
782 * If x is nonnumeric, BESSELI returns the #VALUE! error value.
783 * @param int $ord The order of the Bessel function.
784 * If ord is not an integer, it is truncated.
785 * If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
786 * If $ord < 0, BESSELI returns the #NUM! error value.
787 *
788 * @return float
789 */
790 public static function BESSELI($x, $ord)
791 {
792 $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
793 $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
794
795 if ((is_numeric($x)) && (is_numeric($ord))) {
796 $ord = floor($ord);
797 if ($ord < 0) {
798 return Functions::NAN();
799 }
800
801 if (abs($x) <= 30) {
802 $fResult = $fTerm = pow($x / 2, $ord) / MathTrig::FACT($ord);
803 $ordK = 1;
804 $fSqrX = ($x * $x) / 4;
805 do {
806 $fTerm *= $fSqrX;
807 $fTerm /= ($ordK * ($ordK + $ord));
808 $fResult += $fTerm;
809 } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
810 } else {
811 $f_2_PI = 2 * M_PI;
812
813 $fXAbs = abs($x);
814 $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
815 if (($ord & 1) && ($x < 0)) {
816 $fResult = -$fResult;
817 }
818 }
819
820 return (is_nan($fResult)) ? Functions::NAN() : $fResult;
821 }
822
823 return Functions::VALUE();
824 }
825
826 /**
827 * BESSELJ.
828 *
829 * Returns the Bessel function
830 *
831 * Excel Function:
832 * BESSELJ(x,ord)
833 *
834 * @category Engineering Functions
835 *
836 * @param float $x The value at which to evaluate the function.
837 * If x is nonnumeric, BESSELJ returns the #VALUE! error value.
838 * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
839 * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
840 * If $ord < 0, BESSELJ returns the #NUM! error value.
841 *
842 * @return float
843 */
844 public static function BESSELJ($x, $ord)
845 {
846 $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
847 $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
848
849 if ((is_numeric($x)) && (is_numeric($ord))) {
850 $ord = floor($ord);
851 if ($ord < 0) {
852 return Functions::NAN();
853 }
854
855 $fResult = 0;
856 if (abs($x) <= 30) {
857 $fResult = $fTerm = pow($x / 2, $ord) / MathTrig::FACT($ord);
858 $ordK = 1;
859 $fSqrX = ($x * $x) / -4;
860 do {
861 $fTerm *= $fSqrX;
862 $fTerm /= ($ordK * ($ordK + $ord));
863 $fResult += $fTerm;
864 } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
865 } else {
866 $f_PI_DIV_2 = M_PI / 2;
867 $f_PI_DIV_4 = M_PI / 4;
868
869 $fXAbs = abs($x);
870 $fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4);
871 if (($ord & 1) && ($x < 0)) {
872 $fResult = -$fResult;
873 }
874 }
875
876 return (is_nan($fResult)) ? Functions::NAN() : $fResult;
877 }
878
879 return Functions::VALUE();
880 }
881
882 private static function besselK0($fNum)
883 {
884 if ($fNum <= 2) {
885 $fNum2 = $fNum * 0.5;
886 $y = ($fNum2 * $fNum2);
887 $fRet = -log($fNum2) * self::BESSELI($fNum, 0) +
888 (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
889 (0.10750e-3 + $y * 0.74e-5))))));
890 } else {
891 $y = 2 / $fNum;
892 $fRet = exp(-$fNum) / sqrt($fNum) *
893 (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
894 (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
895 }
896
897 return $fRet;
898 }
899
900 private static function besselK1($fNum)
901 {
902 if ($fNum <= 2) {
903 $fNum2 = $fNum * 0.5;
904 $y = ($fNum2 * $fNum2);
905 $fRet = log($fNum2) * self::BESSELI($fNum, 1) +
906 (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
907 (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
908 } else {
909 $y = 2 / $fNum;
910 $fRet = exp(-$fNum) / sqrt($fNum) *
911 (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
912 (0.325614e-2 + $y * (-0.68245e-3)))))));
913 }
914
915 return $fRet;
916 }
917
918 /**
919 * BESSELK.
920 *
921 * Returns the modified Bessel function Kn(x), which is equivalent to the Bessel functions evaluated
922 * for purely imaginary arguments.
923 *
924 * Excel Function:
925 * BESSELK(x,ord)
926 *
927 * @category Engineering Functions
928 *
929 * @param float $x The value at which to evaluate the function.
930 * If x is nonnumeric, BESSELK returns the #VALUE! error value.
931 * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
932 * If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
933 * If $ord < 0, BESSELK returns the #NUM! error value.
934 *
935 * @return float
936 */
937 public static function BESSELK($x, $ord)
938 {
939 $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
940 $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
941
942 if ((is_numeric($x)) && (is_numeric($ord))) {
943 if (($ord < 0) || ($x == 0.0)) {
944 return Functions::NAN();
945 }
946
947 switch (floor($ord)) {
948 case 0:
949 $fBk = self::besselK0($x);
950
951 break;
952 case 1:
953 $fBk = self::besselK1($x);
954
955 break;
956 default:
957 $fTox = 2 / $x;
958 $fBkm = self::besselK0($x);
959 $fBk = self::besselK1($x);
960 for ($n = 1; $n < $ord; ++$n) {
961 $fBkp = $fBkm + $n * $fTox * $fBk;
962 $fBkm = $fBk;
963 $fBk = $fBkp;
964 }
965 }
966
967 return (is_nan($fBk)) ? Functions::NAN() : $fBk;
968 }
969
970 return Functions::VALUE();
971 }
972
973 private static function besselY0($fNum)
974 {
975 if ($fNum < 8.0) {
976 $y = ($fNum * $fNum);
977 $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733))));
978 $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y))));
979 $fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum);
980 } else {
981 $z = 8.0 / $fNum;
982 $y = ($z * $z);
983 $xx = $fNum - 0.785398164;
984 $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
985 $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7))));
986 $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
987 }
988
989 return $fRet;
990 }
991
992 private static function besselY1($fNum)
993 {
994 if ($fNum < 8.0) {
995 $y = ($fNum * $fNum);
996 $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y *
997 (-0.4237922726e7 + $y * 0.8511937935e4)))));
998 $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
999 (0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
1000 $fRet = $f1 / $f2 + 0.636619772 * (self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
1001 } else {
1002 $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
1003 }
1004
1005 return $fRet;
1006 }
1007
1008 /**
1009 * BESSELY.
1010 *
1011 * Returns the Bessel function, which is also called the Weber function or the Neumann function.
1012 *
1013 * Excel Function:
1014 * BESSELY(x,ord)
1015 *
1016 * @category Engineering Functions
1017 *
1018 * @param float $x The value at which to evaluate the function.
1019 * If x is nonnumeric, BESSELK returns the #VALUE! error value.
1020 * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
1021 * If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
1022 * If $ord < 0, BESSELK returns the #NUM! error value.
1023 *
1024 * @return float
1025 */
1026 public static function BESSELY($x, $ord)
1027 {
1028 $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
1029 $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
1030
1031 if ((is_numeric($x)) && (is_numeric($ord))) {
1032 if (($ord < 0) || ($x == 0.0)) {
1033 return Functions::NAN();
1034 }
1035
1036 switch (floor($ord)) {
1037 case 0:
1038 $fBy = self::besselY0($x);
1039
1040 break;
1041 case 1:
1042 $fBy = self::besselY1($x);
1043
1044 break;
1045 default:
1046 $fTox = 2 / $x;
1047 $fBym = self::besselY0($x);
1048 $fBy = self::besselY1($x);
1049 for ($n = 1; $n < $ord; ++$n) {
1050 $fByp = $n * $fTox * $fBy - $fBym;
1051 $fBym = $fBy;
1052 $fBy = $fByp;
1053 }
1054 }
1055
1056 return (is_nan($fBy)) ? Functions::NAN() : $fBy;
1057 }
1058
1059 return Functions::VALUE();
1060 }
1061
1062 /**
1063 * BINTODEC.
1064 *
1065 * Return a binary value as decimal.
1066 *
1067 * Excel Function:
1068 * BIN2DEC(x)
1069 *
1070 * @category Engineering Functions
1071 *
1072 * @param string $x The binary number (as a string) that you want to convert. The number
1073 * cannot contain more than 10 characters (10 bits). The most significant
1074 * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1075 * Negative numbers are represented using two's-complement notation.
1076 * If number is not a valid binary number, or if number contains more than
1077 * 10 characters (10 bits), BIN2DEC returns the #NUM! error value.
1078 *
1079 * @return string
1080 */
1081 public static function BINTODEC($x)
1082 {
1083 $x = Functions::flattenSingleValue($x);
1084
1085 if (is_bool($x)) {
1086 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1087 $x = (int) $x;
1088 } else {
1089 return Functions::VALUE();
1090 }
1091 }
1092 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1093 $x = floor($x);
1094 }
1095 $x = (string) $x;
1096 if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1097 return Functions::NAN();
1098 }
1099 if (strlen($x) > 10) {
1100 return Functions::NAN();
1101 } elseif (strlen($x) == 10) {
1102 // Two's Complement
1103 $x = substr($x, -9);
1104
1105 return '-' . (512 - bindec($x));
1106 }
1107
1108 return bindec($x);
1109 }
1110
1111 /**
1112 * BINTOHEX.
1113 *
1114 * Return a binary value as hex.
1115 *
1116 * Excel Function:
1117 * BIN2HEX(x[,places])
1118 *
1119 * @category Engineering Functions
1120 *
1121 * @param string $x The binary number (as a string) that you want to convert. The number
1122 * cannot contain more than 10 characters (10 bits). The most significant
1123 * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1124 * Negative numbers are represented using two's-complement notation.
1125 * If number is not a valid binary number, or if number contains more than
1126 * 10 characters (10 bits), BIN2HEX returns the #NUM! error value.
1127 * @param int $places The number of characters to use. If places is omitted, BIN2HEX uses the
1128 * minimum number of characters necessary. Places is useful for padding the
1129 * return value with leading 0s (zeros).
1130 * If places is not an integer, it is truncated.
1131 * If places is nonnumeric, BIN2HEX returns the #VALUE! error value.
1132 * If places is negative, BIN2HEX returns the #NUM! error value.
1133 *
1134 * @return string
1135 */
1136 public static function BINTOHEX($x, $places = null)
1137 {
1138 $x = Functions::flattenSingleValue($x);
1139 $places = Functions::flattenSingleValue($places);
1140
1141 // Argument X
1142 if (is_bool($x)) {
1143 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1144 $x = (int) $x;
1145 } else {
1146 return Functions::VALUE();
1147 }
1148 }
1149 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1150 $x = floor($x);
1151 }
1152 $x = (string) $x;
1153 if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1154 return Functions::NAN();
1155 }
1156 if (strlen($x) > 10) {
1157 return Functions::NAN();
1158 } elseif (strlen($x) == 10) {
1159 // Two's Complement
1160 return str_repeat('F', 8) . substr(strtoupper(dechex(bindec(substr($x, -9)))), -2);
1161 }
1162 $hexVal = (string) strtoupper(dechex(bindec($x)));
1163
1164 return self::nbrConversionFormat($hexVal, $places);
1165 }
1166
1167 /**
1168 * BINTOOCT.
1169 *
1170 * Return a binary value as octal.
1171 *
1172 * Excel Function:
1173 * BIN2OCT(x[,places])
1174 *
1175 * @category Engineering Functions
1176 *
1177 * @param string $x The binary number (as a string) that you want to convert. The number
1178 * cannot contain more than 10 characters (10 bits). The most significant
1179 * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
1180 * Negative numbers are represented using two's-complement notation.
1181 * If number is not a valid binary number, or if number contains more than
1182 * 10 characters (10 bits), BIN2OCT returns the #NUM! error value.
1183 * @param int $places The number of characters to use. If places is omitted, BIN2OCT uses the
1184 * minimum number of characters necessary. Places is useful for padding the
1185 * return value with leading 0s (zeros).
1186 * If places is not an integer, it is truncated.
1187 * If places is nonnumeric, BIN2OCT returns the #VALUE! error value.
1188 * If places is negative, BIN2OCT returns the #NUM! error value.
1189 *
1190 * @return string
1191 */
1192 public static function BINTOOCT($x, $places = null)
1193 {
1194 $x = Functions::flattenSingleValue($x);
1195 $places = Functions::flattenSingleValue($places);
1196
1197 if (is_bool($x)) {
1198 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1199 $x = (int) $x;
1200 } else {
1201 return Functions::VALUE();
1202 }
1203 }
1204 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1205 $x = floor($x);
1206 }
1207 $x = (string) $x;
1208 if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
1209 return Functions::NAN();
1210 }
1211 if (strlen($x) > 10) {
1212 return Functions::NAN();
1213 } elseif (strlen($x) == 10) {
1214 // Two's Complement
1215 return str_repeat('7', 7) . substr(strtoupper(decoct(bindec(substr($x, -9)))), -3);
1216 }
1217 $octVal = (string) decoct(bindec($x));
1218
1219 return self::nbrConversionFormat($octVal, $places);
1220 }
1221
1222 /**
1223 * DECTOBIN.
1224 *
1225 * Return a decimal value as binary.
1226 *
1227 * Excel Function:
1228 * DEC2BIN(x[,places])
1229 *
1230 * @category Engineering Functions
1231 *
1232 * @param string $x The decimal integer you want to convert. If number is negative,
1233 * valid place values are ignored and DEC2BIN returns a 10-character
1234 * (10-bit) binary number in which the most significant bit is the sign
1235 * bit. The remaining 9 bits are magnitude bits. Negative numbers are
1236 * represented using two's-complement notation.
1237 * If number < -512 or if number > 511, DEC2BIN returns the #NUM! error
1238 * value.
1239 * If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
1240 * If DEC2BIN requires more than places characters, it returns the #NUM!
1241 * error value.
1242 * @param int $places The number of characters to use. If places is omitted, DEC2BIN uses
1243 * the minimum number of characters necessary. Places is useful for
1244 * padding the return value with leading 0s (zeros).
1245 * If places is not an integer, it is truncated.
1246 * If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
1247 * If places is zero or negative, DEC2BIN returns the #NUM! error value.
1248 *
1249 * @return string
1250 */
1251 public static function DECTOBIN($x, $places = null)
1252 {
1253 $x = Functions::flattenSingleValue($x);
1254 $places = Functions::flattenSingleValue($places);
1255
1256 if (is_bool($x)) {
1257 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1258 $x = (int) $x;
1259 } else {
1260 return Functions::VALUE();
1261 }
1262 }
1263 $x = (string) $x;
1264 if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1265 return Functions::VALUE();
1266 }
1267
1268 $x = (string) floor($x);
1269 if ($x < -512 || $x > 511) {
1270 return Functions::NAN();
1271 }
1272
1273 $r = decbin($x);
1274 // Two's Complement
1275 $r = substr($r, -10);
1276 if (strlen($r) >= 11) {
1277 return Functions::NAN();
1278 }
1279
1280 return self::nbrConversionFormat($r, $places);
1281 }
1282
1283 /**
1284 * DECTOHEX.
1285 *
1286 * Return a decimal value as hex.
1287 *
1288 * Excel Function:
1289 * DEC2HEX(x[,places])
1290 *
1291 * @category Engineering Functions
1292 *
1293 * @param string $x The decimal integer you want to convert. If number is negative,
1294 * places is ignored and DEC2HEX returns a 10-character (40-bit)
1295 * hexadecimal number in which the most significant bit is the sign
1296 * bit. The remaining 39 bits are magnitude bits. Negative numbers
1297 * are represented using two's-complement notation.
1298 * If number < -549,755,813,888 or if number > 549,755,813,887,
1299 * DEC2HEX returns the #NUM! error value.
1300 * If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
1301 * If DEC2HEX requires more than places characters, it returns the
1302 * #NUM! error value.
1303 * @param int $places The number of characters to use. If places is omitted, DEC2HEX uses
1304 * the minimum number of characters necessary. Places is useful for
1305 * padding the return value with leading 0s (zeros).
1306 * If places is not an integer, it is truncated.
1307 * If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
1308 * If places is zero or negative, DEC2HEX returns the #NUM! error value.
1309 *
1310 * @return string
1311 */
1312 public static function DECTOHEX($x, $places = null)
1313 {
1314 $x = Functions::flattenSingleValue($x);
1315 $places = Functions::flattenSingleValue($places);
1316
1317 if (is_bool($x)) {
1318 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1319 $x = (int) $x;
1320 } else {
1321 return Functions::VALUE();
1322 }
1323 }
1324 $x = (string) $x;
1325 if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1326 return Functions::VALUE();
1327 }
1328 $x = (string) floor($x);
1329 $r = strtoupper(dechex($x));
1330 if (strlen($r) == 8) {
1331 // Two's Complement
1332 $r = 'FF' . $r;
1333 }
1334
1335 return self::nbrConversionFormat($r, $places);
1336 }
1337
1338 /**
1339 * DECTOOCT.
1340 *
1341 * Return an decimal value as octal.
1342 *
1343 * Excel Function:
1344 * DEC2OCT(x[,places])
1345 *
1346 * @category Engineering Functions
1347 *
1348 * @param string $x The decimal integer you want to convert. If number is negative,
1349 * places is ignored and DEC2OCT returns a 10-character (30-bit)
1350 * octal number in which the most significant bit is the sign bit.
1351 * The remaining 29 bits are magnitude bits. Negative numbers are
1352 * represented using two's-complement notation.
1353 * If number < -536,870,912 or if number > 536,870,911, DEC2OCT
1354 * returns the #NUM! error value.
1355 * If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
1356 * If DEC2OCT requires more than places characters, it returns the
1357 * #NUM! error value.
1358 * @param int $places The number of characters to use. If places is omitted, DEC2OCT uses
1359 * the minimum number of characters necessary. Places is useful for
1360 * padding the return value with leading 0s (zeros).
1361 * If places is not an integer, it is truncated.
1362 * If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
1363 * If places is zero or negative, DEC2OCT returns the #NUM! error value.
1364 *
1365 * @return string
1366 */
1367 public static function DECTOOCT($x, $places = null)
1368 {
1369 $xorig = $x;
1370 $x = Functions::flattenSingleValue($x);
1371 $places = Functions::flattenSingleValue($places);
1372
1373 if (is_bool($x)) {
1374 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
1375 $x = (int) $x;
1376 } else {
1377 return Functions::VALUE();
1378 }
1379 }
1380 $x = (string) $x;
1381 if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
1382 return Functions::VALUE();
1383 }
1384 $x = (string) floor($x);
1385 $r = decoct($x);
1386 if (strlen($r) == 11) {
1387 // Two's Complement
1388 $r = substr($r, -10);
1389 }
1390
1391 return self::nbrConversionFormat($r, $places);
1392 }
1393
1394 /**
1395 * HEXTOBIN.
1396 *
1397 * Return a hex value as binary.
1398 *
1399 * Excel Function:
1400 * HEX2BIN(x[,places])
1401 *
1402 * @category Engineering Functions
1403 *
1404 * @param string $x the hexadecimal number you want to convert.
1405 * Number cannot contain more than 10 characters.
1406 * The most significant bit of number is the sign bit (40th bit from the right).
1407 * The remaining 9 bits are magnitude bits.
1408 * Negative numbers are represented using two's-complement notation.
1409 * If number is negative, HEX2BIN ignores places and returns a 10-character binary number.
1410 * If number is negative, it cannot be less than FFFFFFFE00,
1411 * and if number is positive, it cannot be greater than 1FF.
1412 * If number is not a valid hexadecimal number, HEX2BIN returns the #NUM! error value.
1413 * If HEX2BIN requires more than places characters, it returns the #NUM! error value.
1414 * @param int $places The number of characters to use. If places is omitted,
1415 * HEX2BIN uses the minimum number of characters necessary. Places
1416 * is useful for padding the return value with leading 0s (zeros).
1417 * If places is not an integer, it is truncated.
1418 * If places is nonnumeric, HEX2BIN returns the #VALUE! error value.
1419 * If places is negative, HEX2BIN returns the #NUM! error value.
1420 *
1421 * @return string
1422 */
1423 public static function HEXTOBIN($x, $places = null)
1424 {
1425 $x = Functions::flattenSingleValue($x);
1426 $places = Functions::flattenSingleValue($places);
1427
1428 if (is_bool($x)) {
1429 return Functions::VALUE();
1430 }
1431 $x = (string) $x;
1432 if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1433 return Functions::NAN();
1434 }
1435
1436 return self::DECTOBIN(self::HEXTODEC($x), $places);
1437 }
1438
1439 /**
1440 * HEXTODEC.
1441 *
1442 * Return a hex value as decimal.
1443 *
1444 * Excel Function:
1445 * HEX2DEC(x)
1446 *
1447 * @category Engineering Functions
1448 *
1449 * @param string $x The hexadecimal number you want to convert. This number cannot
1450 * contain more than 10 characters (40 bits). The most significant
1451 * bit of number is the sign bit. The remaining 39 bits are magnitude
1452 * bits. Negative numbers are represented using two's-complement
1453 * notation.
1454 * If number is not a valid hexadecimal number, HEX2DEC returns the
1455 * #NUM! error value.
1456 *
1457 * @return string
1458 */
1459 public static function HEXTODEC($x)
1460 {
1461 $x = Functions::flattenSingleValue($x);
1462
1463 if (is_bool($x)) {
1464 return Functions::VALUE();
1465 }
1466 $x = (string) $x;
1467 if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1468 return Functions::NAN();
1469 }
1470
1471 if (strlen($x) > 10) {
1472 return Functions::NAN();
1473 }
1474
1475 $binX = '';
1476 foreach (str_split($x) as $char) {
1477 $binX .= str_pad(base_convert($char, 16, 2), 4, '0', STR_PAD_LEFT);
1478 }
1479 if (strlen($binX) == 40 && $binX[0] == '1') {
1480 for ($i = 0; $i < 40; ++$i) {
1481 $binX[$i] = ($binX[$i] == '1' ? '0' : '1');
1482 }
1483
1484 return (bindec($binX) + 1) * -1;
1485 }
1486
1487 return bindec($binX);
1488 }
1489
1490 /**
1491 * HEXTOOCT.
1492 *
1493 * Return a hex value as octal.
1494 *
1495 * Excel Function:
1496 * HEX2OCT(x[,places])
1497 *
1498 * @category Engineering Functions
1499 *
1500 * @param string $x The hexadecimal number you want to convert. Number cannot
1501 * contain more than 10 characters. The most significant bit of
1502 * number is the sign bit. The remaining 39 bits are magnitude
1503 * bits. Negative numbers are represented using two's-complement
1504 * notation.
1505 * If number is negative, HEX2OCT ignores places and returns a
1506 * 10-character octal number.
1507 * If number is negative, it cannot be less than FFE0000000, and
1508 * if number is positive, it cannot be greater than 1FFFFFFF.
1509 * If number is not a valid hexadecimal number, HEX2OCT returns
1510 * the #NUM! error value.
1511 * If HEX2OCT requires more than places characters, it returns
1512 * the #NUM! error value.
1513 * @param int $places The number of characters to use. If places is omitted, HEX2OCT
1514 * uses the minimum number of characters necessary. Places is
1515 * useful for padding the return value with leading 0s (zeros).
1516 * If places is not an integer, it is truncated.
1517 * If places is nonnumeric, HEX2OCT returns the #VALUE! error
1518 * value.
1519 * If places is negative, HEX2OCT returns the #NUM! error value.
1520 *
1521 * @return string
1522 */
1523 public static function HEXTOOCT($x, $places = null)
1524 {
1525 $x = Functions::flattenSingleValue($x);
1526 $places = Functions::flattenSingleValue($places);
1527
1528 if (is_bool($x)) {
1529 return Functions::VALUE();
1530 }
1531 $x = (string) $x;
1532 if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
1533 return Functions::NAN();
1534 }
1535
1536 $decimal = self::HEXTODEC($x);
1537 if ($decimal < -536870912 || $decimal > 536870911) {
1538 return Functions::NAN();
1539 }
1540
1541 return self::DECTOOCT($decimal, $places);
1542 }
1543
1544 /**
1545 * OCTTOBIN.
1546 *
1547 * Return an octal value as binary.
1548 *
1549 * Excel Function:
1550 * OCT2BIN(x[,places])
1551 *
1552 * @category Engineering Functions
1553 *
1554 * @param string $x The octal number you want to convert. Number may not
1555 * contain more than 10 characters. The most significant
1556 * bit of number is the sign bit. The remaining 29 bits
1557 * are magnitude bits. Negative numbers are represented
1558 * using two's-complement notation.
1559 * If number is negative, OCT2BIN ignores places and returns
1560 * a 10-character binary number.
1561 * If number is negative, it cannot be less than 7777777000,
1562 * and if number is positive, it cannot be greater than 777.
1563 * If number is not a valid octal number, OCT2BIN returns
1564 * the #NUM! error value.
1565 * If OCT2BIN requires more than places characters, it
1566 * returns the #NUM! error value.
1567 * @param int $places The number of characters to use. If places is omitted,
1568 * OCT2BIN uses the minimum number of characters necessary.
1569 * Places is useful for padding the return value with
1570 * leading 0s (zeros).
1571 * If places is not an integer, it is truncated.
1572 * If places is nonnumeric, OCT2BIN returns the #VALUE!
1573 * error value.
1574 * If places is negative, OCT2BIN returns the #NUM! error
1575 * value.
1576 *
1577 * @return string
1578 */
1579 public static function OCTTOBIN($x, $places = null)
1580 {
1581 $x = Functions::flattenSingleValue($x);
1582 $places = Functions::flattenSingleValue($places);
1583
1584 if (is_bool($x)) {
1585 return Functions::VALUE();
1586 }
1587 $x = (string) $x;
1588 if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1589 return Functions::NAN();
1590 }
1591
1592 return self::DECTOBIN(self::OCTTODEC($x), $places);
1593 }
1594
1595 /**
1596 * OCTTODEC.
1597 *
1598 * Return an octal value as decimal.
1599 *
1600 * Excel Function:
1601 * OCT2DEC(x)
1602 *
1603 * @category Engineering Functions
1604 *
1605 * @param string $x The octal number you want to convert. Number may not contain
1606 * more than 10 octal characters (30 bits). The most significant
1607 * bit of number is the sign bit. The remaining 29 bits are
1608 * magnitude bits. Negative numbers are represented using
1609 * two's-complement notation.
1610 * If number is not a valid octal number, OCT2DEC returns the
1611 * #NUM! error value.
1612 *
1613 * @return string
1614 */
1615 public static function OCTTODEC($x)
1616 {
1617 $x = Functions::flattenSingleValue($x);
1618
1619 if (is_bool($x)) {
1620 return Functions::VALUE();
1621 }
1622 $x = (string) $x;
1623 if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1624 return Functions::NAN();
1625 }
1626 $binX = '';
1627 foreach (str_split($x) as $char) {
1628 $binX .= str_pad(decbin((int) $char), 3, '0', STR_PAD_LEFT);
1629 }
1630 if (strlen($binX) == 30 && $binX[0] == '1') {
1631 for ($i = 0; $i < 30; ++$i) {
1632 $binX[$i] = ($binX[$i] == '1' ? '0' : '1');
1633 }
1634
1635 return (bindec($binX) + 1) * -1;
1636 }
1637
1638 return bindec($binX);
1639 }
1640
1641 /**
1642 * OCTTOHEX.
1643 *
1644 * Return an octal value as hex.
1645 *
1646 * Excel Function:
1647 * OCT2HEX(x[,places])
1648 *
1649 * @category Engineering Functions
1650 *
1651 * @param string $x The octal number you want to convert. Number may not contain
1652 * more than 10 octal characters (30 bits). The most significant
1653 * bit of number is the sign bit. The remaining 29 bits are
1654 * magnitude bits. Negative numbers are represented using
1655 * two's-complement notation.
1656 * If number is negative, OCT2HEX ignores places and returns a
1657 * 10-character hexadecimal number.
1658 * If number is not a valid octal number, OCT2HEX returns the
1659 * #NUM! error value.
1660 * If OCT2HEX requires more than places characters, it returns
1661 * the #NUM! error value.
1662 * @param int $places The number of characters to use. If places is omitted, OCT2HEX
1663 * uses the minimum number of characters necessary. Places is useful
1664 * for padding the return value with leading 0s (zeros).
1665 * If places is not an integer, it is truncated.
1666 * If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
1667 * If places is negative, OCT2HEX returns the #NUM! error value.
1668 *
1669 * @return string
1670 */
1671 public static function OCTTOHEX($x, $places = null)
1672 {
1673 $x = Functions::flattenSingleValue($x);
1674 $places = Functions::flattenSingleValue($places);
1675
1676 if (is_bool($x)) {
1677 return Functions::VALUE();
1678 }
1679 $x = (string) $x;
1680 if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
1681 return Functions::NAN();
1682 }
1683 $hexVal = strtoupper(dechex(self::OCTTODEC($x)));
1684
1685 return self::nbrConversionFormat($hexVal, $places);
1686 }
1687
1688 /**
1689 * COMPLEX.
1690 *
1691 * Converts real and imaginary coefficients into a complex number of the form x +/- yi or x +/- yj.
1692 *
1693 * Excel Function:
1694 * COMPLEX(realNumber,imaginary[,suffix])
1695 *
1696 * @category Engineering Functions
1697 *
1698 * @param float $realNumber the real coefficient of the complex number
1699 * @param float $imaginary the imaginary coefficient of the complex number
1700 * @param string $suffix The suffix for the imaginary component of the complex number.
1701 * If omitted, the suffix is assumed to be "i".
1702 *
1703 * @return string
1704 */
1705 public static function COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i')
1706 {
1707 $realNumber = ($realNumber === null) ? 0.0 : Functions::flattenSingleValue($realNumber);
1708 $imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary);
1709 $suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix);
1710
1711 if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
1712 (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))
1713 ) {
1714 $complex = new Complex($realNumber, $imaginary, $suffix);
1715
1716 return (string) $complex;
1717 }
1718
1719 return Functions::VALUE();
1720 }
1721
1722 /**
1723 * IMAGINARY.
1724 *
1725 * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
1726 *
1727 * Excel Function:
1728 * IMAGINARY(complexNumber)
1729 *
1730 * @category Engineering Functions
1731 *
1732 * @param string $complexNumber the complex number for which you want the imaginary
1733 * coefficient
1734 *
1735 * @return float
1736 */
1737 public static function IMAGINARY($complexNumber)
1738 {
1739 $complexNumber = Functions::flattenSingleValue($complexNumber);
1740
1741 return (new Complex($complexNumber))->getImaginary();
1742 }
1743
1744 /**
1745 * IMREAL.
1746 *
1747 * Returns the real coefficient of a complex number in x + yi or x + yj text format.
1748 *
1749 * Excel Function:
1750 * IMREAL(complexNumber)
1751 *
1752 * @category Engineering Functions
1753 *
1754 * @param string $complexNumber the complex number for which you want the real coefficient
1755 *
1756 * @return float
1757 */
1758 public static function IMREAL($complexNumber)
1759 {
1760 $complexNumber = Functions::flattenSingleValue($complexNumber);
1761
1762 return (new Complex($complexNumber))->getReal();
1763 }
1764
1765 /**
1766 * IMABS.
1767 *
1768 * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
1769 *
1770 * Excel Function:
1771 * IMABS(complexNumber)
1772 *
1773 * @param string $complexNumber the complex number for which you want the absolute value
1774 *
1775 * @return float
1776 */
1777 public static function IMABS($complexNumber)
1778 {
1779 $complexNumber = Functions::flattenSingleValue($complexNumber);
1780
1781 return (new Complex($complexNumber))->abs();
1782 }
1783
1784 /**
1785 * IMARGUMENT.
1786 *
1787 * Returns the argument theta of a complex number, i.e. the angle in radians from the real
1788 * axis to the representation of the number in polar coordinates.
1789 *
1790 * Excel Function:
1791 * IMARGUMENT(complexNumber)
1792 *
1793 * @param string $complexNumber the complex number for which you want the argument theta
1794 *
1795 * @return float|string
1796 */
1797 public static function IMARGUMENT($complexNumber)
1798 {
1799 $complexNumber = Functions::flattenSingleValue($complexNumber);
1800
1801 $complex = new Complex($complexNumber);
1802 if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
1803 return Functions::DIV0();
1804 }
1805
1806 return $complex->argument();
1807 }
1808
1809 /**
1810 * IMCONJUGATE.
1811 *
1812 * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
1813 *
1814 * Excel Function:
1815 * IMCONJUGATE(complexNumber)
1816 *
1817 * @param string $complexNumber the complex number for which you want the conjugate
1818 *
1819 * @return string
1820 */
1821 public static function IMCONJUGATE($complexNumber)
1822 {
1823 $complexNumber = Functions::flattenSingleValue($complexNumber);
1824
1825 return (string) (new Complex($complexNumber))->conjugate();
1826 }
1827
1828 /**
1829 * IMCOS.
1830 *
1831 * Returns the cosine of a complex number in x + yi or x + yj text format.
1832 *
1833 * Excel Function:
1834 * IMCOS(complexNumber)
1835 *
1836 * @param string $complexNumber the complex number for which you want the cosine
1837 *
1838 * @return float|string
1839 */
1840 public static function IMCOS($complexNumber)
1841 {
1842 $complexNumber = Functions::flattenSingleValue($complexNumber);
1843
1844 return (string) (new Complex($complexNumber))->cos();
1845 }
1846
1847 /**
1848 * IMCOSH.
1849 *
1850 * Returns the hyperbolic cosine of a complex number in x + yi or x + yj text format.
1851 *
1852 * Excel Function:
1853 * IMCOSH(complexNumber)
1854 *
1855 * @param string $complexNumber the complex number for which you want the hyperbolic cosine
1856 *
1857 * @return float|string
1858 */
1859 public static function IMCOSH($complexNumber)
1860 {
1861 $complexNumber = Functions::flattenSingleValue($complexNumber);
1862
1863 return (string) (new Complex($complexNumber))->cosh();
1864 }
1865
1866 /**
1867 * IMCOT.
1868 *
1869 * Returns the cotangent of a complex number in x + yi or x + yj text format.
1870 *
1871 * Excel Function:
1872 * IMCOT(complexNumber)
1873 *
1874 * @param string $complexNumber the complex number for which you want the cotangent
1875 *
1876 * @return float|string
1877 */
1878 public static function IMCOT($complexNumber)
1879 {
1880 $complexNumber = Functions::flattenSingleValue($complexNumber);
1881
1882 return (string) (new Complex($complexNumber))->cot();
1883 }
1884
1885 /**
1886 * IMCSC.
1887 *
1888 * Returns the cosecant of a complex number in x + yi or x + yj text format.
1889 *
1890 * Excel Function:
1891 * IMCSC(complexNumber)
1892 *
1893 * @param string $complexNumber the complex number for which you want the cosecant
1894 *
1895 * @return float|string
1896 */
1897 public static function IMCSC($complexNumber)
1898 {
1899 $complexNumber = Functions::flattenSingleValue($complexNumber);
1900
1901 return (string) (new Complex($complexNumber))->csc();
1902 }
1903
1904 /**
1905 * IMCSCH.
1906 *
1907 * Returns the hyperbolic cosecant of a complex number in x + yi or x + yj text format.
1908 *
1909 * Excel Function:
1910 * IMCSCH(complexNumber)
1911 *
1912 * @param string $complexNumber the complex number for which you want the hyperbolic cosecant
1913 *
1914 * @return float|string
1915 */
1916 public static function IMCSCH($complexNumber)
1917 {
1918 $complexNumber = Functions::flattenSingleValue($complexNumber);
1919
1920 return (string) (new Complex($complexNumber))->csch();
1921 }
1922
1923 /**
1924 * IMSIN.
1925 *
1926 * Returns the sine of a complex number in x + yi or x + yj text format.
1927 *
1928 * Excel Function:
1929 * IMSIN(complexNumber)
1930 *
1931 * @param string $complexNumber the complex number for which you want the sine
1932 *
1933 * @return float|string
1934 */
1935 public static function IMSIN($complexNumber)
1936 {
1937 $complexNumber = Functions::flattenSingleValue($complexNumber);
1938
1939 return (string) (new Complex($complexNumber))->sin();
1940 }
1941
1942 /**
1943 * IMSINH.
1944 *
1945 * Returns the hyperbolic sine of a complex number in x + yi or x + yj text format.
1946 *
1947 * Excel Function:
1948 * IMSINH(complexNumber)
1949 *
1950 * @param string $complexNumber the complex number for which you want the hyperbolic sine
1951 *
1952 * @return float|string
1953 */
1954 public static function IMSINH($complexNumber)
1955 {
1956 $complexNumber = Functions::flattenSingleValue($complexNumber);
1957
1958 return (string) (new Complex($complexNumber))->sinh();
1959 }
1960
1961 /**
1962 * IMSEC.
1963 *
1964 * Returns the secant of a complex number in x + yi or x + yj text format.
1965 *
1966 * Excel Function:
1967 * IMSEC(complexNumber)
1968 *
1969 * @param string $complexNumber the complex number for which you want the secant
1970 *
1971 * @return float|string
1972 */
1973 public static function IMSEC($complexNumber)
1974 {
1975 $complexNumber = Functions::flattenSingleValue($complexNumber);
1976
1977 return (string) (new Complex($complexNumber))->sec();
1978 }
1979
1980 /**
1981 * IMSECH.
1982 *
1983 * Returns the hyperbolic secant of a complex number in x + yi or x + yj text format.
1984 *
1985 * Excel Function:
1986 * IMSECH(complexNumber)
1987 *
1988 * @param string $complexNumber the complex number for which you want the hyperbolic secant
1989 *
1990 * @return float|string
1991 */
1992 public static function IMSECH($complexNumber)
1993 {
1994 $complexNumber = Functions::flattenSingleValue($complexNumber);
1995
1996 return (string) (new Complex($complexNumber))->sech();
1997 }
1998
1999 /**
2000 * IMTAN.
2001 *
2002 * Returns the tangent of a complex number in x + yi or x + yj text format.
2003 *
2004 * Excel Function:
2005 * IMTAN(complexNumber)
2006 *
2007 * @param string $complexNumber the complex number for which you want the tangent
2008 *
2009 * @return float|string
2010 */
2011 public static function IMTAN($complexNumber)
2012 {
2013 $complexNumber = Functions::flattenSingleValue($complexNumber);
2014
2015 return (string) (new Complex($complexNumber))->tan();
2016 }
2017
2018 /**
2019 * IMSQRT.
2020 *
2021 * Returns the square root of a complex number in x + yi or x + yj text format.
2022 *
2023 * Excel Function:
2024 * IMSQRT(complexNumber)
2025 *
2026 * @param string $complexNumber the complex number for which you want the square root
2027 *
2028 * @return string
2029 */
2030 public static function IMSQRT($complexNumber)
2031 {
2032 $complexNumber = Functions::flattenSingleValue($complexNumber);
2033
2034 $theta = self::IMARGUMENT($complexNumber);
2035 if ($theta === Functions::DIV0()) {
2036 return '0';
2037 }
2038
2039 return (string) (new Complex($complexNumber))->sqrt();
2040 }
2041
2042 /**
2043 * IMLN.
2044 *
2045 * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
2046 *
2047 * Excel Function:
2048 * IMLN(complexNumber)
2049 *
2050 * @param string $complexNumber the complex number for which you want the natural logarithm
2051 *
2052 * @return string
2053 */
2054 public static function IMLN($complexNumber)
2055 {
2056 $complexNumber = Functions::flattenSingleValue($complexNumber);
2057
2058 $complex = new Complex($complexNumber);
2059 if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
2060 return Functions::NAN();
2061 }
2062
2063 return (string) (new Complex($complexNumber))->ln();
2064 }
2065
2066 /**
2067 * IMLOG10.
2068 *
2069 * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
2070 *
2071 * Excel Function:
2072 * IMLOG10(complexNumber)
2073 *
2074 * @param string $complexNumber the complex number for which you want the common logarithm
2075 *
2076 * @return string
2077 */
2078 public static function IMLOG10($complexNumber)
2079 {
2080 $complexNumber = Functions::flattenSingleValue($complexNumber);
2081
2082 $complex = new Complex($complexNumber);
2083 if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
2084 return Functions::NAN();
2085 }
2086
2087 return (string) (new Complex($complexNumber))->log10();
2088 }
2089
2090 /**
2091 * IMLOG2.
2092 *
2093 * Returns the base-2 logarithm of a complex number in x + yi or x + yj text format.
2094 *
2095 * Excel Function:
2096 * IMLOG2(complexNumber)
2097 *
2098 * @param string $complexNumber the complex number for which you want the base-2 logarithm
2099 *
2100 * @return string
2101 */
2102 public static function IMLOG2($complexNumber)
2103 {
2104 $complexNumber = Functions::flattenSingleValue($complexNumber);
2105
2106 $complex = new Complex($complexNumber);
2107 if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
2108 return Functions::NAN();
2109 }
2110
2111 return (string) (new Complex($complexNumber))->log2();
2112 }
2113
2114 /**
2115 * IMEXP.
2116 *
2117 * Returns the exponential of a complex number in x + yi or x + yj text format.
2118 *
2119 * Excel Function:
2120 * IMEXP(complexNumber)
2121 *
2122 * @param string $complexNumber the complex number for which you want the exponential
2123 *
2124 * @return string
2125 */
2126 public static function IMEXP($complexNumber)
2127 {
2128 $complexNumber = Functions::flattenSingleValue($complexNumber);
2129
2130 return (string) (new Complex($complexNumber))->exp();
2131 }
2132
2133 /**
2134 * IMPOWER.
2135 *
2136 * Returns a complex number in x + yi or x + yj text format raised to a power.
2137 *
2138 * Excel Function:
2139 * IMPOWER(complexNumber,realNumber)
2140 *
2141 * @param string $complexNumber the complex number you want to raise to a power
2142 * @param float $realNumber the power to which you want to raise the complex number
2143 *
2144 * @return string
2145 */
2146 public static function IMPOWER($complexNumber, $realNumber)
2147 {
2148 $complexNumber = Functions::flattenSingleValue($complexNumber);
2149 $realNumber = Functions::flattenSingleValue($realNumber);
2150
2151 if (!is_numeric($realNumber)) {
2152 return Functions::VALUE();
2153 }
2154
2155 return (string) (new Complex($complexNumber))->pow($realNumber);
2156 }
2157
2158 /**
2159 * IMDIV.
2160 *
2161 * Returns the quotient of two complex numbers in x + yi or x + yj text format.
2162 *
2163 * Excel Function:
2164 * IMDIV(complexDividend,complexDivisor)
2165 *
2166 * @param string $complexDividend the complex numerator or dividend
2167 * @param string $complexDivisor the complex denominator or divisor
2168 *
2169 * @return string
2170 */
2171 public static function IMDIV($complexDividend, $complexDivisor)
2172 {
2173 $complexDividend = Functions::flattenSingleValue($complexDividend);
2174 $complexDivisor = Functions::flattenSingleValue($complexDivisor);
2175
2176 try {
2177 return (string) (new Complex($complexDividend))->divideby(new Complex($complexDivisor));
2178 } catch (ComplexException $e) {
2179 return Functions::NAN();
2180 }
2181 }
2182
2183 /**
2184 * IMSUB.
2185 *
2186 * Returns the difference of two complex numbers in x + yi or x + yj text format.
2187 *
2188 * Excel Function:
2189 * IMSUB(complexNumber1,complexNumber2)
2190 *
2191 * @param string $complexNumber1 the complex number from which to subtract complexNumber2
2192 * @param string $complexNumber2 the complex number to subtract from complexNumber1
2193 *
2194 * @return string
2195 */
2196 public static function IMSUB($complexNumber1, $complexNumber2)
2197 {
2198 $complexNumber1 = Functions::flattenSingleValue($complexNumber1);
2199 $complexNumber2 = Functions::flattenSingleValue($complexNumber2);
2200
2201 try {
2202 return (string) (new Complex($complexNumber1))->subtract(new Complex($complexNumber2));
2203 } catch (ComplexException $e) {
2204 return Functions::NAN();
2205 }
2206 }
2207
2208 /**
2209 * IMSUM.
2210 *
2211 * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
2212 *
2213 * Excel Function:
2214 * IMSUM(complexNumber[,complexNumber[,...]])
2215 *
2216 * @param string ...$complexNumbers Series of complex numbers to add
2217 *
2218 * @return string
2219 */
2220 public static function IMSUM(...$complexNumbers)
2221 {
2222 // Return value
2223 $returnValue = new Complex(0.0);
2224 $aArgs = Functions::flattenArray($complexNumbers);
2225
2226 try {
2227 // Loop through the arguments
2228 foreach ($aArgs as $complex) {
2229 $returnValue = $returnValue->add(new Complex($complex));
2230 }
2231 } catch (ComplexException $e) {
2232 return Functions::NAN();
2233 }
2234
2235 return (string) $returnValue;
2236 }
2237
2238 /**
2239 * IMPRODUCT.
2240 *
2241 * Returns the product of two or more complex numbers in x + yi or x + yj text format.
2242 *
2243 * Excel Function:
2244 * IMPRODUCT(complexNumber[,complexNumber[,...]])
2245 *
2246 * @param string ...$complexNumbers Series of complex numbers to multiply
2247 *
2248 * @return string
2249 */
2250 public static function IMPRODUCT(...$complexNumbers)
2251 {
2252 // Return value
2253 $returnValue = new Complex(1.0);
2254 $aArgs = Functions::flattenArray($complexNumbers);
2255
2256 try {
2257 // Loop through the arguments
2258 foreach ($aArgs as $complex) {
2259 $returnValue = $returnValue->multiply(new Complex($complex));
2260 }
2261 } catch (ComplexException $e) {
2262 return Functions::NAN();
2263 }
2264
2265 return (string) $returnValue;
2266 }
2267
2268 /**
2269 * DELTA.
2270 *
2271 * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
2272 * Use this function to filter a set of values. For example, by summing several DELTA
2273 * functions you calculate the count of equal pairs. This function is also known as the
2274 * Kronecker Delta function.
2275 *
2276 * Excel Function:
2277 * DELTA(a[,b])
2278 *
2279 * @param float $a the first number
2280 * @param float $b The second number. If omitted, b is assumed to be zero.
2281 *
2282 * @return int
2283 */
2284 public static function DELTA($a, $b = 0)
2285 {
2286 $a = Functions::flattenSingleValue($a);
2287 $b = Functions::flattenSingleValue($b);
2288
2289 return (int) ($a == $b);
2290 }
2291
2292 /**
2293 * GESTEP.
2294 *
2295 * Excel Function:
2296 * GESTEP(number[,step])
2297 *
2298 * Returns 1 if number >= step; returns 0 (zero) otherwise
2299 * Use this function to filter a set of values. For example, by summing several GESTEP
2300 * functions you calculate the count of values that exceed a threshold.
2301 *
2302 * @param float $number the value to test against step
2303 * @param float $step The threshold value.
2304 * If you omit a value for step, GESTEP uses zero.
2305 *
2306 * @return int
2307 */
2308 public static function GESTEP($number, $step = 0)
2309 {
2310 $number = Functions::flattenSingleValue($number);
2311 $step = Functions::flattenSingleValue($step);
2312
2313 return (int) ($number >= $step);
2314 }
2315
2316 //
2317 // Private method to calculate the erf value
2318 //
2319 private static $twoSqrtPi = 1.128379167095512574;
2320
2321 public static function erfVal($x)
2322 {
2323 if (abs($x) > 2.2) {
2324 return 1 - self::erfcVal($x);
2325 }
2326 $sum = $term = $x;
2327 $xsqr = ($x * $x);
2328 $j = 1;
2329 do {
2330 $term *= $xsqr / $j;
2331 $sum -= $term / (2 * $j + 1);
2332 ++$j;
2333 $term *= $xsqr / $j;
2334 $sum += $term / (2 * $j + 1);
2335 ++$j;
2336 if ($sum == 0.0) {
2337 break;
2338 }
2339 } while (abs($term / $sum) > Functions::PRECISION);
2340
2341 return self::$twoSqrtPi * $sum;
2342 }
2343
2344 /**
2345 * Validate arguments passed to the bitwise functions.
2346 *
2347 * @param mixed $value
2348 *
2349 * @throws Exception
2350 *
2351 * @return int
2352 */
2353 private static function validateBitwiseArgument($value)
2354 {
2355 $value = Functions::flattenSingleValue($value);
2356
2357 if (is_int($value)) {
2358 return $value;
2359 } elseif (is_numeric($value)) {
2360 if ($value == (int) ($value)) {
2361 $value = (int) ($value);
2362 if (($value > pow(2, 48) - 1) || ($value < 0)) {
2363 throw new Exception(Functions::NAN());
2364 }
2365
2366 return $value;
2367 }
2368
2369 throw new Exception(Functions::NAN());
2370 }
2371
2372 throw new Exception(Functions::VALUE());
2373 }
2374
2375 /**
2376 * BITAND.
2377 *
2378 * Returns the bitwise AND of two integer values.
2379 *
2380 * Excel Function:
2381 * BITAND(number1, number2)
2382 *
2383 * @category Engineering Functions
2384 *
2385 * @param int $number1
2386 * @param int $number2
2387 *
2388 * @return int|string
2389 */
2390 public static function BITAND($number1, $number2)
2391 {
2392 try {
2393 $number1 = self::validateBitwiseArgument($number1);
2394 $number2 = self::validateBitwiseArgument($number2);
2395 } catch (Exception $e) {
2396 return $e->getMessage();
2397 }
2398
2399 return $number1 & $number2;
2400 }
2401
2402 /**
2403 * BITOR.
2404 *
2405 * Returns the bitwise OR of two integer values.
2406 *
2407 * Excel Function:
2408 * BITOR(number1, number2)
2409 *
2410 * @category Engineering Functions
2411 *
2412 * @param int $number1
2413 * @param int $number2
2414 *
2415 * @return int|string
2416 */
2417 public static function BITOR($number1, $number2)
2418 {
2419 try {
2420 $number1 = self::validateBitwiseArgument($number1);
2421 $number2 = self::validateBitwiseArgument($number2);
2422 } catch (Exception $e) {
2423 return $e->getMessage();
2424 }
2425
2426 return $number1 | $number2;
2427 }
2428
2429 /**
2430 * BITXOR.
2431 *
2432 * Returns the bitwise XOR of two integer values.
2433 *
2434 * Excel Function:
2435 * BITXOR(number1, number2)
2436 *
2437 * @category Engineering Functions
2438 *
2439 * @param int $number1
2440 * @param int $number2
2441 *
2442 * @return int|string
2443 */
2444 public static function BITXOR($number1, $number2)
2445 {
2446 try {
2447 $number1 = self::validateBitwiseArgument($number1);
2448 $number2 = self::validateBitwiseArgument($number2);
2449 } catch (Exception $e) {
2450 return $e->getMessage();
2451 }
2452
2453 return $number1 ^ $number2;
2454 }
2455
2456 /**
2457 * BITLSHIFT.
2458 *
2459 * Returns the number value shifted left by shift_amount bits.
2460 *
2461 * Excel Function:
2462 * BITLSHIFT(number, shift_amount)
2463 *
2464 * @category Engineering Functions
2465 *
2466 * @param int $number
2467 * @param int $shiftAmount
2468 *
2469 * @return int|string
2470 */
2471 public static function BITLSHIFT($number, $shiftAmount)
2472 {
2473 try {
2474 $number = self::validateBitwiseArgument($number);
2475 } catch (Exception $e) {
2476 return $e->getMessage();
2477 }
2478
2479 $shiftAmount = Functions::flattenSingleValue($shiftAmount);
2480
2481 $result = $number << $shiftAmount;
2482 if ($result > pow(2, 48) - 1) {
2483 return Functions::NAN();
2484 }
2485
2486 return $result;
2487 }
2488
2489 /**
2490 * BITRSHIFT.
2491 *
2492 * Returns the number value shifted right by shift_amount bits.
2493 *
2494 * Excel Function:
2495 * BITRSHIFT(number, shift_amount)
2496 *
2497 * @category Engineering Functions
2498 *
2499 * @param int $number
2500 * @param int $shiftAmount
2501 *
2502 * @return int|string
2503 */
2504 public static function BITRSHIFT($number, $shiftAmount)
2505 {
2506 try {
2507 $number = self::validateBitwiseArgument($number);
2508 } catch (Exception $e) {
2509 return $e->getMessage();
2510 }
2511
2512 $shiftAmount = Functions::flattenSingleValue($shiftAmount);
2513
2514 return $number >> $shiftAmount;
2515 }
2516
2517 /**
2518 * ERF.
2519 *
2520 * Returns the error function integrated between the lower and upper bound arguments.
2521 *
2522 * Note: In Excel 2007 or earlier, if you input a negative value for the upper or lower bound arguments,
2523 * the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
2524 * improved, so that it can now calculate the function for both positive and negative ranges.
2525 * PhpSpreadsheet follows Excel 2010 behaviour, and accepts negative arguments.
2526 *
2527 * Excel Function:
2528 * ERF(lower[,upper])
2529 *
2530 * @param float $lower lower bound for integrating ERF
2531 * @param float $upper upper bound for integrating ERF.
2532 * If omitted, ERF integrates between zero and lower_limit
2533 *
2534 * @return float|string
2535 */
2536 public static function ERF($lower, $upper = null)
2537 {
2538 $lower = Functions::flattenSingleValue($lower);
2539 $upper = Functions::flattenSingleValue($upper);
2540
2541 if (is_numeric($lower)) {
2542 if ($upper === null) {
2543 return self::erfVal($lower);
2544 }
2545 if (is_numeric($upper)) {
2546 return self::erfVal($upper) - self::erfVal($lower);
2547 }
2548 }
2549
2550 return Functions::VALUE();
2551 }
2552
2553 /**
2554 * ERFPRECISE.
2555 *
2556 * Returns the error function integrated between the lower and upper bound arguments.
2557 *
2558 * Excel Function:
2559 * ERF.PRECISE(limit)
2560 *
2561 * @param float $limit bound for integrating ERF
2562 *
2563 * @return float|string
2564 */
2565 public static function ERFPRECISE($limit)
2566 {
2567 $limit = Functions::flattenSingleValue($limit);
2568
2569 return self::ERF($limit);
2570 }
2571
2572 //
2573 // Private method to calculate the erfc value
2574 //
2575 private static $oneSqrtPi = 0.564189583547756287;
2576
2577 private static function erfcVal($x)
2578 {
2579 if (abs($x) < 2.2) {
2580 return 1 - self::erfVal($x);
2581 }
2582 if ($x < 0) {
2583 return 2 - self::ERFC(-$x);
2584 }
2585 $a = $n = 1;
2586 $b = $c = $x;
2587 $d = ($x * $x) + 0.5;
2588 $q1 = $q2 = $b / $d;
2589 $t = 0;
2590 do {
2591 $t = $a * $n + $b * $x;
2592 $a = $b;
2593 $b = $t;
2594 $t = $c * $n + $d * $x;
2595 $c = $d;
2596 $d = $t;
2597 $n += 0.5;
2598 $q1 = $q2;
2599 $q2 = $b / $d;
2600 } while ((abs($q1 - $q2) / $q2) > Functions::PRECISION);
2601
2602 return self::$oneSqrtPi * exp(-$x * $x) * $q2;
2603 }
2604
2605 /**
2606 * ERFC.
2607 *
2608 * Returns the complementary ERF function integrated between x and infinity
2609 *
2610 * Note: In Excel 2007 or earlier, if you input a negative value for the lower bound argument,
2611 * the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
2612 * improved, so that it can now calculate the function for both positive and negative x values.
2613 * PhpSpreadsheet follows Excel 2010 behaviour, and accepts nagative arguments.
2614 *
2615 * Excel Function:
2616 * ERFC(x)
2617 *
2618 * @param float $x The lower bound for integrating ERFC
2619 *
2620 * @return float|string
2621 */
2622 public static function ERFC($x)
2623 {
2624 $x = Functions::flattenSingleValue($x);
2625
2626 if (is_numeric($x)) {
2627 return self::erfcVal($x);
2628 }
2629
2630 return Functions::VALUE();
2631 }
2632
2633 /**
2634 * getConversionGroups
2635 * Returns a list of the different conversion groups for UOM conversions.
2636 *
2637 * @return array
2638 */
2639 public static function getConversionGroups()
2640 {
2641 $conversionGroups = [];
2642 foreach (self::$conversionUnits as $conversionUnit) {
2643 $conversionGroups[] = $conversionUnit['Group'];
2644 }
2645
2646 return array_merge(array_unique($conversionGroups));
2647 }
2648
2649 /**
2650 * getConversionGroupUnits
2651 * Returns an array of units of measure, for a specified conversion group, or for all groups.
2652 *
2653 * @param string $group The group whose units of measure you want to retrieve
2654 *
2655 * @return array
2656 */
2657 public static function getConversionGroupUnits($group = null)
2658 {
2659 $conversionGroups = [];
2660 foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
2661 if (($group === null) || ($conversionGroup['Group'] == $group)) {
2662 $conversionGroups[$conversionGroup['Group']][] = $conversionUnit;
2663 }
2664 }
2665
2666 return $conversionGroups;
2667 }
2668
2669 /**
2670 * getConversionGroupUnitDetails.
2671 *
2672 * @param string $group The group whose units of measure you want to retrieve
2673 *
2674 * @return array
2675 */
2676 public static function getConversionGroupUnitDetails($group = null)
2677 {
2678 $conversionGroups = [];
2679 foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
2680 if (($group === null) || ($conversionGroup['Group'] == $group)) {
2681 $conversionGroups[$conversionGroup['Group']][] = [
2682 'unit' => $conversionUnit,
2683 'description' => $conversionGroup['Unit Name'],
2684 ];
2685 }
2686 }
2687
2688 return $conversionGroups;
2689 }
2690
2691 /**
2692 * getConversionMultipliers
2693 * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
2694 *
2695 * @return array of mixed
2696 */
2697 public static function getConversionMultipliers()
2698 {
2699 return self::$conversionMultipliers;
2700 }
2701
2702 /**
2703 * CONVERTUOM.
2704 *
2705 * Converts a number from one measurement system to another.
2706 * For example, CONVERT can translate a table of distances in miles to a table of distances
2707 * in kilometers.
2708 *
2709 * Excel Function:
2710 * CONVERT(value,fromUOM,toUOM)
2711 *
2712 * @param float $value the value in fromUOM to convert
2713 * @param string $fromUOM the units for value
2714 * @param string $toUOM the units for the result
2715 *
2716 * @return float
2717 */
2718 public static function CONVERTUOM($value, $fromUOM, $toUOM)
2719 {
2720 $value = Functions::flattenSingleValue($value);
2721 $fromUOM = Functions::flattenSingleValue($fromUOM);
2722 $toUOM = Functions::flattenSingleValue($toUOM);
2723
2724 if (!is_numeric($value)) {
2725 return Functions::VALUE();
2726 }
2727 $fromMultiplier = 1.0;
2728 if (isset(self::$conversionUnits[$fromUOM])) {
2729 $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
2730 } else {
2731 $fromMultiplier = substr($fromUOM, 0, 1);
2732 $fromUOM = substr($fromUOM, 1);
2733 if (isset(self::$conversionMultipliers[$fromMultiplier])) {
2734 $fromMultiplier = self::$conversionMultipliers[$fromMultiplier]['multiplier'];
2735 } else {
2736 return Functions::NA();
2737 }
2738 if ((isset(self::$conversionUnits[$fromUOM])) && (self::$conversionUnits[$fromUOM]['AllowPrefix'])) {
2739 $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
2740 } else {
2741 return Functions::NA();
2742 }
2743 }
2744 $value *= $fromMultiplier;
2745
2746 $toMultiplier = 1.0;
2747 if (isset(self::$conversionUnits[$toUOM])) {
2748 $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
2749 } else {
2750 $toMultiplier = substr($toUOM, 0, 1);
2751 $toUOM = substr($toUOM, 1);
2752 if (isset(self::$conversionMultipliers[$toMultiplier])) {
2753 $toMultiplier = self::$conversionMultipliers[$toMultiplier]['multiplier'];
2754 } else {
2755 return Functions::NA();
2756 }
2757 if ((isset(self::$conversionUnits[$toUOM])) && (self::$conversionUnits[$toUOM]['AllowPrefix'])) {
2758 $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
2759 } else {
2760 return Functions::NA();
2761 }
2762 }
2763 if ($unitGroup1 != $unitGroup2) {
2764 return Functions::NA();
2765 }
2766
2767 if (($fromUOM == $toUOM) && ($fromMultiplier == $toMultiplier)) {
2768 // We've already factored $fromMultiplier into the value, so we need
2769 // to reverse it again
2770 return $value / $fromMultiplier;
2771 } elseif ($unitGroup1 == 'Temperature') {
2772 if (($fromUOM == 'F') || ($fromUOM == 'fah')) {
2773 if (($toUOM == 'F') || ($toUOM == 'fah')) {
2774 return $value;
2775 }
2776 $value = (($value - 32) / 1.8);
2777 if (($toUOM == 'K') || ($toUOM == 'kel')) {
2778 $value += 273.15;
2779 }
2780
2781 return $value;
2782 } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) &&
2783 (($toUOM == 'K') || ($toUOM == 'kel'))
2784 ) {
2785 return $value;
2786 } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) &&
2787 (($toUOM == 'C') || ($toUOM == 'cel'))
2788 ) {
2789 return $value;
2790 }
2791 if (($toUOM == 'F') || ($toUOM == 'fah')) {
2792 if (($fromUOM == 'K') || ($fromUOM == 'kel')) {
2793 $value -= 273.15;
2794 }
2795
2796 return ($value * 1.8) + 32;
2797 }
2798 if (($toUOM == 'C') || ($toUOM == 'cel')) {
2799 return $value - 273.15;
2800 }
2801
2802 return $value + 273.15;
2803 }
2804
2805 return ($value * self::$unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier;
2806 }
2807 }
2808