For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2650 lines
108 KiB

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