arrayops_meat.hpp 19 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
  2. // Copyright 2008-2016 National ICT Australia (NICTA)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ------------------------------------------------------------------------
  15. //! \addtogroup arrayops
  16. //! @{
  17. template<typename eT>
  18. arma_hot
  19. arma_inline
  20. void
  21. arrayops::copy(eT* dest, const eT* src, const uword n_elem)
  22. {
  23. if(is_cx<eT>::no)
  24. {
  25. if(n_elem <= 9)
  26. {
  27. arrayops::copy_small(dest, src, n_elem);
  28. }
  29. else
  30. {
  31. std::memcpy(dest, src, n_elem*sizeof(eT));
  32. }
  33. }
  34. else
  35. {
  36. if(n_elem > 0) { std::memcpy(dest, src, n_elem*sizeof(eT)); }
  37. }
  38. }
  39. template<typename eT>
  40. arma_cold
  41. inline
  42. void
  43. arrayops::copy_small(eT* dest, const eT* src, const uword n_elem)
  44. {
  45. switch(n_elem)
  46. {
  47. case 9: dest[ 8] = src[ 8];
  48. // fallthrough
  49. case 8: dest[ 7] = src[ 7];
  50. // fallthrough
  51. case 7: dest[ 6] = src[ 6];
  52. // fallthrough
  53. case 6: dest[ 5] = src[ 5];
  54. // fallthrough
  55. case 5: dest[ 4] = src[ 4];
  56. // fallthrough
  57. case 4: dest[ 3] = src[ 3];
  58. // fallthrough
  59. case 3: dest[ 2] = src[ 2];
  60. // fallthrough
  61. case 2: dest[ 1] = src[ 1];
  62. // fallthrough
  63. case 1: dest[ 0] = src[ 0];
  64. // fallthrough
  65. default: ;
  66. }
  67. }
  68. template<typename eT>
  69. inline
  70. void
  71. arrayops::fill_zeros(eT* dest, const uword n_elem)
  72. {
  73. typedef typename get_pod_type<eT>::result pod_type;
  74. if(std::numeric_limits<eT>::is_integer || std::numeric_limits<pod_type>::is_iec559)
  75. {
  76. if(n_elem > 0) { std::memset((void*)dest, 0, sizeof(eT)*n_elem); }
  77. }
  78. else
  79. {
  80. arrayops::inplace_set_simple(dest, eT(0), n_elem);
  81. }
  82. }
  83. template<typename eT>
  84. arma_hot
  85. inline
  86. void
  87. arrayops::replace(eT* mem, const uword n_elem, const eT old_val, const eT new_val)
  88. {
  89. if(arma_isnan(old_val))
  90. {
  91. for(uword i=0; i<n_elem; ++i)
  92. {
  93. eT& val = mem[i];
  94. val = (arma_isnan(val)) ? new_val : val;
  95. }
  96. }
  97. else
  98. {
  99. for(uword i=0; i<n_elem; ++i)
  100. {
  101. eT& val = mem[i];
  102. val = (val == old_val) ? new_val : val;
  103. }
  104. }
  105. }
  106. template<typename eT>
  107. arma_hot
  108. inline
  109. void
  110. arrayops::clean(eT* mem, const uword n_elem, const eT abs_limit, const typename arma_not_cx<eT>::result* junk)
  111. {
  112. arma_ignore(junk);
  113. for(uword i=0; i<n_elem; ++i)
  114. {
  115. eT& val = mem[i];
  116. val = (eop_aux::arma_abs(val) <= abs_limit) ? eT(0) : val;
  117. }
  118. }
  119. template<typename T>
  120. arma_hot
  121. inline
  122. void
  123. arrayops::clean(std::complex<T>* mem, const uword n_elem, const T abs_limit)
  124. {
  125. typedef typename std::complex<T> eT;
  126. for(uword i=0; i<n_elem; ++i)
  127. {
  128. eT& val = mem[i];
  129. T val_real = std::real(val);
  130. T val_imag = std::imag(val);
  131. if(std::abs(val_real) <= abs_limit)
  132. {
  133. val_imag = (std::abs(val_imag) <= abs_limit) ? T(0) : val_imag;
  134. val = std::complex<T>(T(0), val_imag);
  135. }
  136. else
  137. if(std::abs(val_imag) <= abs_limit)
  138. {
  139. val = std::complex<T>(val_real, T(0));
  140. }
  141. }
  142. }
  143. template<typename out_eT, typename in_eT>
  144. arma_hot
  145. arma_inline
  146. void
  147. arrayops::convert_cx_scalar
  148. (
  149. out_eT& out,
  150. const in_eT& in,
  151. const typename arma_not_cx<out_eT>::result* junk1,
  152. const typename arma_not_cx< in_eT>::result* junk2
  153. )
  154. {
  155. arma_ignore(junk1);
  156. arma_ignore(junk2);
  157. out = out_eT(in);
  158. }
  159. template<typename out_eT, typename in_T>
  160. arma_hot
  161. arma_inline
  162. void
  163. arrayops::convert_cx_scalar
  164. (
  165. out_eT& out,
  166. const std::complex<in_T>& in,
  167. const typename arma_not_cx<out_eT>::result* junk
  168. )
  169. {
  170. arma_ignore(junk);
  171. out = out_eT( in.real() );
  172. }
  173. template<typename out_T, typename in_T>
  174. arma_hot
  175. arma_inline
  176. void
  177. arrayops::convert_cx_scalar
  178. (
  179. std::complex<out_T>& out,
  180. const std::complex< in_T>& in
  181. )
  182. {
  183. typedef std::complex<out_T> out_eT;
  184. out = out_eT(in);
  185. }
  186. template<typename out_eT, typename in_eT>
  187. arma_hot
  188. inline
  189. void
  190. arrayops::convert(out_eT* dest, const in_eT* src, const uword n_elem)
  191. {
  192. if(is_same_type<out_eT,in_eT>::value)
  193. {
  194. const out_eT* src2 = (const out_eT*)src;
  195. if(dest != src2) { arrayops::copy(dest, src2, n_elem); }
  196. return;
  197. }
  198. uword j;
  199. for(j=1; j<n_elem; j+=2)
  200. {
  201. const in_eT tmp_i = (*src); src++;
  202. const in_eT tmp_j = (*src); src++;
  203. // dest[i] = out_eT( tmp_i );
  204. // dest[j] = out_eT( tmp_j );
  205. (*dest) = (is_signed<out_eT>::value)
  206. ? out_eT( tmp_i )
  207. : ( cond_rel< is_signed<in_eT>::value >::lt(tmp_i, in_eT(0)) ? out_eT(0) : out_eT(tmp_i) );
  208. dest++;
  209. (*dest) = (is_signed<out_eT>::value)
  210. ? out_eT( tmp_j )
  211. : ( cond_rel< is_signed<in_eT>::value >::lt(tmp_j, in_eT(0)) ? out_eT(0) : out_eT(tmp_j) );
  212. dest++;
  213. }
  214. if((j-1) < n_elem)
  215. {
  216. const in_eT tmp_i = (*src);
  217. // dest[i] = out_eT( tmp_i );
  218. (*dest) = (is_signed<out_eT>::value)
  219. ? out_eT( tmp_i )
  220. : ( cond_rel< is_signed<in_eT>::value >::lt(tmp_i, in_eT(0)) ? out_eT(0) : out_eT(tmp_i) );
  221. }
  222. }
  223. template<typename out_eT, typename in_eT>
  224. arma_hot
  225. inline
  226. void
  227. arrayops::convert_cx(out_eT* dest, const in_eT* src, const uword n_elem)
  228. {
  229. uword j;
  230. for(j=1; j<n_elem; j+=2)
  231. {
  232. arrayops::convert_cx_scalar( (*dest), (*src) ); dest++; src++;
  233. arrayops::convert_cx_scalar( (*dest), (*src) ); dest++; src++;
  234. }
  235. if((j-1) < n_elem)
  236. {
  237. arrayops::convert_cx_scalar( (*dest), (*src) );
  238. }
  239. }
  240. template<typename eT>
  241. arma_hot
  242. inline
  243. void
  244. arrayops::inplace_plus(eT* dest, const eT* src, const uword n_elem)
  245. {
  246. if(memory::is_aligned(dest))
  247. {
  248. memory::mark_as_aligned(dest);
  249. if(memory::is_aligned(src))
  250. {
  251. memory::mark_as_aligned(src);
  252. arrayops::inplace_plus_base(dest, src, n_elem);
  253. }
  254. else
  255. {
  256. arrayops::inplace_plus_base(dest, src, n_elem);
  257. }
  258. }
  259. else
  260. {
  261. if(memory::is_aligned(src))
  262. {
  263. memory::mark_as_aligned(src);
  264. arrayops::inplace_plus_base(dest, src, n_elem);
  265. }
  266. else
  267. {
  268. arrayops::inplace_plus_base(dest, src, n_elem);
  269. }
  270. }
  271. }
  272. template<typename eT>
  273. arma_hot
  274. inline
  275. void
  276. arrayops::inplace_minus(eT* dest, const eT* src, const uword n_elem)
  277. {
  278. if(memory::is_aligned(dest))
  279. {
  280. memory::mark_as_aligned(dest);
  281. if(memory::is_aligned(src))
  282. {
  283. memory::mark_as_aligned(src);
  284. arrayops::inplace_minus_base(dest, src, n_elem);
  285. }
  286. else
  287. {
  288. arrayops::inplace_minus_base(dest, src, n_elem);
  289. }
  290. }
  291. else
  292. {
  293. if(memory::is_aligned(src))
  294. {
  295. memory::mark_as_aligned(src);
  296. arrayops::inplace_minus_base(dest, src, n_elem);
  297. }
  298. else
  299. {
  300. arrayops::inplace_minus_base(dest, src, n_elem);
  301. }
  302. }
  303. }
  304. template<typename eT>
  305. arma_hot
  306. inline
  307. void
  308. arrayops::inplace_mul(eT* dest, const eT* src, const uword n_elem)
  309. {
  310. if(memory::is_aligned(dest))
  311. {
  312. memory::mark_as_aligned(dest);
  313. if(memory::is_aligned(src))
  314. {
  315. memory::mark_as_aligned(src);
  316. arrayops::inplace_mul_base(dest, src, n_elem);
  317. }
  318. else
  319. {
  320. arrayops::inplace_mul_base(dest, src, n_elem);
  321. }
  322. }
  323. else
  324. {
  325. if(memory::is_aligned(src))
  326. {
  327. memory::mark_as_aligned(src);
  328. arrayops::inplace_mul_base(dest, src, n_elem);
  329. }
  330. else
  331. {
  332. arrayops::inplace_mul_base(dest, src, n_elem);
  333. }
  334. }
  335. }
  336. template<typename eT>
  337. arma_hot
  338. inline
  339. void
  340. arrayops::inplace_div(eT* dest, const eT* src, const uword n_elem)
  341. {
  342. if(memory::is_aligned(dest))
  343. {
  344. memory::mark_as_aligned(dest);
  345. if(memory::is_aligned(src))
  346. {
  347. memory::mark_as_aligned(src);
  348. arrayops::inplace_div_base(dest, src, n_elem);
  349. }
  350. else
  351. {
  352. arrayops::inplace_div_base(dest, src, n_elem);
  353. }
  354. }
  355. else
  356. {
  357. if(memory::is_aligned(src))
  358. {
  359. memory::mark_as_aligned(src);
  360. arrayops::inplace_div_base(dest, src, n_elem);
  361. }
  362. else
  363. {
  364. arrayops::inplace_div_base(dest, src, n_elem);
  365. }
  366. }
  367. }
  368. template<typename eT>
  369. arma_hot
  370. inline
  371. void
  372. arrayops::inplace_plus_base(eT* dest, const eT* src, const uword n_elem)
  373. {
  374. #if defined(ARMA_SIMPLE_LOOPS)
  375. {
  376. for(uword i=0; i<n_elem; ++i)
  377. {
  378. dest[i] += src[i];
  379. }
  380. }
  381. #else
  382. {
  383. uword i,j;
  384. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  385. {
  386. const eT tmp_i = src[i];
  387. const eT tmp_j = src[j];
  388. dest[i] += tmp_i;
  389. dest[j] += tmp_j;
  390. }
  391. if(i < n_elem)
  392. {
  393. dest[i] += src[i];
  394. }
  395. }
  396. #endif
  397. }
  398. template<typename eT>
  399. arma_hot
  400. inline
  401. void
  402. arrayops::inplace_minus_base(eT* dest, const eT* src, const uword n_elem)
  403. {
  404. #if defined(ARMA_SIMPLE_LOOPS)
  405. {
  406. for(uword i=0; i<n_elem; ++i)
  407. {
  408. dest[i] -= src[i];
  409. }
  410. }
  411. #else
  412. {
  413. uword i,j;
  414. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  415. {
  416. const eT tmp_i = src[i];
  417. const eT tmp_j = src[j];
  418. dest[i] -= tmp_i;
  419. dest[j] -= tmp_j;
  420. }
  421. if(i < n_elem)
  422. {
  423. dest[i] -= src[i];
  424. }
  425. }
  426. #endif
  427. }
  428. template<typename eT>
  429. arma_hot
  430. inline
  431. void
  432. arrayops::inplace_mul_base(eT* dest, const eT* src, const uword n_elem)
  433. {
  434. #if defined(ARMA_SIMPLE_LOOPS)
  435. {
  436. for(uword i=0; i<n_elem; ++i)
  437. {
  438. dest[i] *= src[i];
  439. }
  440. }
  441. #else
  442. {
  443. uword i,j;
  444. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  445. {
  446. const eT tmp_i = src[i];
  447. const eT tmp_j = src[j];
  448. dest[i] *= tmp_i;
  449. dest[j] *= tmp_j;
  450. }
  451. if(i < n_elem)
  452. {
  453. dest[i] *= src[i];
  454. }
  455. }
  456. #endif
  457. }
  458. template<typename eT>
  459. arma_hot
  460. inline
  461. void
  462. arrayops::inplace_div_base(eT* dest, const eT* src, const uword n_elem)
  463. {
  464. #if defined(ARMA_SIMPLE_LOOPS)
  465. {
  466. for(uword i=0; i<n_elem; ++i)
  467. {
  468. dest[i] /= src[i];
  469. }
  470. }
  471. #else
  472. {
  473. uword i,j;
  474. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  475. {
  476. const eT tmp_i = src[i];
  477. const eT tmp_j = src[j];
  478. dest[i] /= tmp_i;
  479. dest[j] /= tmp_j;
  480. }
  481. if(i < n_elem)
  482. {
  483. dest[i] /= src[i];
  484. }
  485. }
  486. #endif
  487. }
  488. template<typename eT>
  489. arma_hot
  490. inline
  491. void
  492. arrayops::inplace_set(eT* dest, const eT val, const uword n_elem)
  493. {
  494. if(val == eT(0))
  495. {
  496. arrayops::fill_zeros(dest, n_elem);
  497. }
  498. else
  499. {
  500. if( (n_elem <= 9) && (is_cx<eT>::no) )
  501. {
  502. arrayops::inplace_set_small(dest, val, n_elem);
  503. }
  504. else
  505. {
  506. arrayops::inplace_set_simple(dest, val, n_elem);
  507. }
  508. }
  509. }
  510. template<typename eT>
  511. arma_hot
  512. inline
  513. void
  514. arrayops::inplace_set_simple(eT* dest, const eT val, const uword n_elem)
  515. {
  516. if(memory::is_aligned(dest))
  517. {
  518. memory::mark_as_aligned(dest);
  519. arrayops::inplace_set_base(dest, val, n_elem);
  520. }
  521. else
  522. {
  523. arrayops::inplace_set_base(dest, val, n_elem);
  524. }
  525. }
  526. template<typename eT>
  527. arma_hot
  528. inline
  529. void
  530. arrayops::inplace_set_base(eT* dest, const eT val, const uword n_elem)
  531. {
  532. #if defined(ARMA_SIMPLE_LOOPS)
  533. {
  534. for(uword i=0; i<n_elem; ++i)
  535. {
  536. dest[i] = val;
  537. }
  538. }
  539. #else
  540. {
  541. uword i,j;
  542. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  543. {
  544. dest[i] = val;
  545. dest[j] = val;
  546. }
  547. if(i < n_elem)
  548. {
  549. dest[i] = val;
  550. }
  551. }
  552. #endif
  553. }
  554. template<typename eT>
  555. arma_cold
  556. inline
  557. void
  558. arrayops::inplace_set_small(eT* dest, const eT val, const uword n_elem)
  559. {
  560. switch(n_elem)
  561. {
  562. case 9: dest[ 8] = val;
  563. // fallthrough
  564. case 8: dest[ 7] = val;
  565. // fallthrough
  566. case 7: dest[ 6] = val;
  567. // fallthrough
  568. case 6: dest[ 5] = val;
  569. // fallthrough
  570. case 5: dest[ 4] = val;
  571. // fallthrough
  572. case 4: dest[ 3] = val;
  573. // fallthrough
  574. case 3: dest[ 2] = val;
  575. // fallthrough
  576. case 2: dest[ 1] = val;
  577. // fallthrough
  578. case 1: dest[ 0] = val;
  579. // fallthrough
  580. default:;
  581. }
  582. }
  583. template<typename eT, const uword n_elem>
  584. arma_hot
  585. inline
  586. void
  587. arrayops::inplace_set_fixed(eT* dest, const eT val)
  588. {
  589. for(uword i=0; i<n_elem; ++i)
  590. {
  591. dest[i] = val;
  592. }
  593. }
  594. template<typename eT>
  595. arma_hot
  596. inline
  597. void
  598. arrayops::inplace_plus(eT* dest, const eT val, const uword n_elem)
  599. {
  600. if(memory::is_aligned(dest))
  601. {
  602. memory::mark_as_aligned(dest);
  603. arrayops::inplace_plus_base(dest, val, n_elem);
  604. }
  605. else
  606. {
  607. arrayops::inplace_plus_base(dest, val, n_elem);
  608. }
  609. }
  610. template<typename eT>
  611. arma_hot
  612. inline
  613. void
  614. arrayops::inplace_minus(eT* dest, const eT val, const uword n_elem)
  615. {
  616. if(memory::is_aligned(dest))
  617. {
  618. memory::mark_as_aligned(dest);
  619. arrayops::inplace_minus_base(dest, val, n_elem);
  620. }
  621. else
  622. {
  623. arrayops::inplace_minus_base(dest, val, n_elem);
  624. }
  625. }
  626. template<typename eT>
  627. arma_hot
  628. inline
  629. void
  630. arrayops::inplace_mul(eT* dest, const eT val, const uword n_elem)
  631. {
  632. if(memory::is_aligned(dest))
  633. {
  634. memory::mark_as_aligned(dest);
  635. arrayops::inplace_mul_base(dest, val, n_elem);
  636. }
  637. else
  638. {
  639. arrayops::inplace_mul_base(dest, val, n_elem);
  640. }
  641. }
  642. template<typename eT>
  643. arma_hot
  644. inline
  645. void
  646. arrayops::inplace_div(eT* dest, const eT val, const uword n_elem)
  647. {
  648. if(memory::is_aligned(dest))
  649. {
  650. memory::mark_as_aligned(dest);
  651. arrayops::inplace_div_base(dest, val, n_elem);
  652. }
  653. else
  654. {
  655. arrayops::inplace_div_base(dest, val, n_elem);
  656. }
  657. }
  658. template<typename eT>
  659. arma_hot
  660. inline
  661. void
  662. arrayops::inplace_plus_base(eT* dest, const eT val, const uword n_elem)
  663. {
  664. #if defined(ARMA_SIMPLE_LOOPS)
  665. {
  666. for(uword i=0; i<n_elem; ++i)
  667. {
  668. dest[i] += val;
  669. }
  670. }
  671. #else
  672. {
  673. uword i,j;
  674. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  675. {
  676. dest[i] += val;
  677. dest[j] += val;
  678. }
  679. if(i < n_elem)
  680. {
  681. dest[i] += val;
  682. }
  683. }
  684. #endif
  685. }
  686. template<typename eT>
  687. arma_hot
  688. inline
  689. void
  690. arrayops::inplace_minus_base(eT* dest, const eT val, const uword n_elem)
  691. {
  692. #if defined(ARMA_SIMPLE_LOOPS)
  693. {
  694. for(uword i=0; i<n_elem; ++i)
  695. {
  696. dest[i] -= val;
  697. }
  698. }
  699. #else
  700. {
  701. uword i,j;
  702. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  703. {
  704. dest[i] -= val;
  705. dest[j] -= val;
  706. }
  707. if(i < n_elem)
  708. {
  709. dest[i] -= val;
  710. }
  711. }
  712. #endif
  713. }
  714. template<typename eT>
  715. arma_hot
  716. inline
  717. void
  718. arrayops::inplace_mul_base(eT* dest, const eT val, const uword n_elem)
  719. {
  720. #if defined(ARMA_SIMPLE_LOOPS)
  721. {
  722. for(uword i=0; i<n_elem; ++i)
  723. {
  724. dest[i] *= val;
  725. }
  726. }
  727. #else
  728. {
  729. uword i,j;
  730. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  731. {
  732. dest[i] *= val;
  733. dest[j] *= val;
  734. }
  735. if(i < n_elem)
  736. {
  737. dest[i] *= val;
  738. }
  739. }
  740. #endif
  741. }
  742. template<typename eT>
  743. arma_hot
  744. inline
  745. void
  746. arrayops::inplace_div_base(eT* dest, const eT val, const uword n_elem)
  747. {
  748. #if defined(ARMA_SIMPLE_LOOPS)
  749. {
  750. for(uword i=0; i<n_elem; ++i)
  751. {
  752. dest[i] /= val;
  753. }
  754. }
  755. #else
  756. {
  757. uword i,j;
  758. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  759. {
  760. dest[i] /= val;
  761. dest[j] /= val;
  762. }
  763. if(i < n_elem)
  764. {
  765. dest[i] /= val;
  766. }
  767. }
  768. #endif
  769. }
  770. template<typename eT>
  771. arma_hot
  772. inline
  773. eT
  774. arrayops::accumulate(const eT* src, const uword n_elem)
  775. {
  776. #if defined(__FINITE_MATH_ONLY__) && (__FINITE_MATH_ONLY__ > 0)
  777. {
  778. eT acc = eT(0);
  779. if(memory::is_aligned(src))
  780. {
  781. memory::mark_as_aligned(src);
  782. for(uword i=0; i<n_elem; ++i) { acc += src[i]; }
  783. }
  784. else
  785. {
  786. for(uword i=0; i<n_elem; ++i) { acc += src[i]; }
  787. }
  788. return acc;
  789. }
  790. #else
  791. {
  792. eT acc1 = eT(0);
  793. eT acc2 = eT(0);
  794. uword j;
  795. for(j=1; j<n_elem; j+=2)
  796. {
  797. acc1 += (*src); src++;
  798. acc2 += (*src); src++;
  799. }
  800. if((j-1) < n_elem)
  801. {
  802. acc1 += (*src);
  803. }
  804. return acc1 + acc2;
  805. }
  806. #endif
  807. }
  808. template<typename eT>
  809. arma_hot
  810. inline
  811. eT
  812. arrayops::product(const eT* src, const uword n_elem)
  813. {
  814. eT val1 = eT(1);
  815. eT val2 = eT(1);
  816. uword i,j;
  817. for(i=0, j=1; j<n_elem; i+=2, j+=2)
  818. {
  819. val1 *= src[i];
  820. val2 *= src[j];
  821. }
  822. if(i < n_elem)
  823. {
  824. val1 *= src[i];
  825. }
  826. return val1 * val2;
  827. }
  828. template<typename eT>
  829. arma_hot
  830. inline
  831. bool
  832. arrayops::is_zero(const eT* mem, const uword n_elem, const eT abs_limit, const typename arma_not_cx<eT>::result* junk)
  833. {
  834. arma_ignore(junk);
  835. if(n_elem == 0) { return false; }
  836. if(abs_limit == eT(0))
  837. {
  838. for(uword i=0; i<n_elem; ++i)
  839. {
  840. if(mem[i] != eT(0)) { return false; }
  841. }
  842. }
  843. else
  844. {
  845. for(uword i=0; i<n_elem; ++i)
  846. {
  847. if(eop_aux::arma_abs(mem[i]) > abs_limit) { return false; }
  848. }
  849. }
  850. return true;
  851. }
  852. template<typename T>
  853. arma_hot
  854. inline
  855. bool
  856. arrayops::is_zero(const std::complex<T>* mem, const uword n_elem, const T abs_limit)
  857. {
  858. typedef typename std::complex<T> eT;
  859. if(n_elem == 0) { return false; }
  860. if(abs_limit == T(0))
  861. {
  862. for(uword i=0; i<n_elem; ++i)
  863. {
  864. const eT& val = mem[i];
  865. if(std::real(val) != T(0)) { return false; }
  866. if(std::imag(val) != T(0)) { return false; }
  867. }
  868. }
  869. else
  870. {
  871. for(uword i=0; i<n_elem; ++i)
  872. {
  873. const eT& val = mem[i];
  874. if(std::abs(std::real(val)) > abs_limit) { return false; }
  875. if(std::abs(std::imag(val)) > abs_limit) { return false; }
  876. }
  877. }
  878. return true;
  879. }
  880. template<typename eT>
  881. arma_hot
  882. inline
  883. bool
  884. arrayops::is_finite(const eT* src, const uword n_elem)
  885. {
  886. uword j;
  887. for(j=1; j<n_elem; j+=2)
  888. {
  889. const eT val_i = (*src); src++;
  890. const eT val_j = (*src); src++;
  891. if( (arma_isfinite(val_i) == false) || (arma_isfinite(val_j) == false) )
  892. {
  893. return false;
  894. }
  895. }
  896. if((j-1) < n_elem)
  897. {
  898. if(arma_isfinite(*src) == false)
  899. {
  900. return false;
  901. }
  902. }
  903. return true;
  904. }
  905. template<typename eT>
  906. arma_hot
  907. inline
  908. bool
  909. arrayops::has_inf(const eT* src, const uword n_elem)
  910. {
  911. uword j;
  912. for(j=1; j<n_elem; j+=2)
  913. {
  914. const eT val_i = (*src); src++;
  915. const eT val_j = (*src); src++;
  916. if( arma_isinf(val_i) || arma_isinf(val_j) ) { return true; }
  917. }
  918. if((j-1) < n_elem)
  919. {
  920. if(arma_isinf(*src)) { return true; }
  921. }
  922. return false;
  923. }
  924. template<typename eT>
  925. arma_hot
  926. inline
  927. bool
  928. arrayops::has_nan(const eT* src, const uword n_elem)
  929. {
  930. uword j;
  931. for(j=1; j<n_elem; j+=2)
  932. {
  933. const eT val_i = (*src); src++;
  934. const eT val_j = (*src); src++;
  935. if( arma_isnan(val_i) || arma_isnan(val_j) ) { return true; }
  936. }
  937. if((j-1) < n_elem)
  938. {
  939. if(arma_isnan(*src)) { return true; }
  940. }
  941. return false;
  942. }
  943. //! @}