PageRenderTime 31ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/monitoring/quicknet-v3_31/QN_fltvec.cc

https://github.com/tjurgens/MAP
C++ | 833 lines | 711 code | 107 blank | 15 comment | 87 complexity | cbacaa9eed524978a765f5575f03f633 MD5 | raw file
  1. const char* QN_fltvec_rcsid = "$Header: /u/drspeech/repos/quicknet2/QN_fltvec.cc,v 1.22 2011/03/15 22:43:47 davidj Exp $";
  2. // Floating point vector utility routines for QuickNet
  3. #include <assert.h>
  4. #include <string.h>
  5. #include "QN_fltvec.h"
  6. #if !QN_HAVE_DECL_DRAND48
  7. extern "C" {
  8. double drand48(void);
  9. }
  10. #endif
  11. QNUInt32 qn_math = QN_MATH_NV;
  12. void
  13. qn_swapb_vd_vd(size_t len, const double *from, double* to)
  14. {
  15. size_t i;
  16. for (i=len; i!=0; i--)
  17. {
  18. QNInt32 *p1 = (QNInt32 *)to++;
  19. QNInt32 *p3 = (QNInt32 *)from++;
  20. QNInt32 *p2 = p1 + 1;
  21. QNInt32 *p4 = p3 + 1;
  22. *p1 = qn_btoh_i32_i32(*p4);
  23. *p2 = qn_btoh_i32_i32(*p3);
  24. }
  25. }
  26. void
  27. qn_urand48_ff_vf(size_t n, float min, float max, float *vec)
  28. {
  29. const float range = max - min;
  30. size_t i;
  31. for (i=0; i<n; i++)
  32. {
  33. *vec++ = ((float) drand48() * range) + min;
  34. }
  35. }
  36. int
  37. qn_findexp_f_i(float f)
  38. {
  39. const double RECIP_LOG_2 = 1.442695040888963;
  40. return (int) ceil(log(fabs(f))*RECIP_LOG_2);
  41. }
  42. void
  43. qn_nv_muladd_vffvf_vf(const size_t n,
  44. const float* xvec, const float s, const float *yvec,
  45. float* res)
  46. {
  47. size_t i;
  48. for (i=0; i<n; i++)
  49. res[i] = s * xvec[i] + yvec[i];
  50. }
  51. void
  52. qn_fe_sigmoid_vf_vf(size_t n, const float* in_vec, float* out_vec)
  53. {
  54. size_t i;
  55. for (i=n; i!=0; i--)
  56. {
  57. *out_vec++ = qn_fe_sigmoid_f_f(*in_vec++);
  58. }
  59. }
  60. // Vector sigmoid using IBM vector routines
  61. #ifdef QN_HAVE_LIBMASS
  62. void
  63. qn_ms_sigmoid_vf_vf(size_t n, const float* in_vec, float* out_vec)
  64. {
  65. size_t i;
  66. int count = n;
  67. float* outp;
  68. outp = out_vec;
  69. for (i=n; i!=0; i--)
  70. {
  71. *outp++ = -(*in_vec++);
  72. }
  73. vsexp(out_vec, out_vec, &count);
  74. outp = out_vec;
  75. for (i=n; i!=0; i--)
  76. {
  77. (*outp++) += 1.0f;
  78. }
  79. vsrec(out_vec, out_vec, &count);
  80. }
  81. #endif
  82. // Vector sigmoid using Intel Math Kernel Library routines
  83. #ifdef QN_HAVE_LIBMKL
  84. void
  85. qn_mk_sigmoid_vf_vf(size_t n, const float* in_vec, float* out_vec)
  86. {
  87. size_t i;
  88. int count = n;
  89. float* outp;
  90. outp = out_vec;
  91. for (i=n; i!=0; i--)
  92. {
  93. *outp++ = -(*in_vec++);
  94. }
  95. vsExp(count, out_vec, out_vec);
  96. outp = out_vec;
  97. for (i=n; i!=0; i--)
  98. {
  99. (*outp++) += 1.0f;
  100. }
  101. vsInv(count, out_vec, out_vec);
  102. }
  103. #endif
  104. void
  105. qn_nv_sigmoid_vf_vf(size_t n, const float* in_vec, float* out_vec)
  106. {
  107. size_t i;
  108. for (i=0; i<n; i++)
  109. {
  110. *out_vec++ = qn_nv_sigmoid_f_f(*in_vec++);
  111. }
  112. }
  113. void
  114. qn_nv_tanh_vf_vf(size_t n, const float* in_vec, float* out_vec)
  115. {
  116. size_t i;
  117. for (i=n; i!=0; i--)
  118. {
  119. *out_vec++ = qn_nv_tanh_f_f(*in_vec++);
  120. }
  121. }
  122. void
  123. qn_fe_tanh_vf_vf(size_t n, const float* in_vec, float* out_vec)
  124. {
  125. size_t i;
  126. for (i=n; i!=0; i--)
  127. {
  128. *out_vec++ = qn_fe_tanh_f_f(*in_vec++);
  129. }
  130. }
  131. void
  132. qn_nv_softmax_vf_vf(size_t n, const float* in_vec, float* out_vec)
  133. {
  134. float max;
  135. float min;
  136. float sumexp = 0.0f; /* Sum of exponents */
  137. float scale; /* 1/sum of exponents */
  138. size_t i;
  139. qn_maxmin_vf_ff(n, in_vec, &max, &min); /* Find constant bias. */
  140. for (i=0; i<n; i++)
  141. {
  142. float f; /* Input value. */
  143. float e; /* Exponent of current value. */
  144. f = in_vec[i];
  145. #ifdef QN_HAVE_EXPF
  146. e = expf(f - max);
  147. #else
  148. e = exp(f - max);
  149. #endif
  150. out_vec[i] = e;
  151. sumexp += e;
  152. }
  153. scale = 1.0f/sumexp;
  154. for (i=0; i<n; i++)
  155. {
  156. out_vec[i] = out_vec[i] * scale;
  157. }
  158. }
  159. void
  160. qn_fe_softmax_vf_vf(size_t n, const float* in_vec, float* out_vec)
  161. {
  162. float max;
  163. float min;
  164. float sumexp = 0.0f; /* Sum of exponents */
  165. float scale; /* 1/sum of exponents */
  166. size_t i;
  167. QN_EXPQ_WORKSPACE;
  168. float* out_vec2 = out_vec;
  169. qn_maxmin_vf_ff(n, in_vec, &max, &min); /* Find constant bias. */
  170. for (i=n; i!=0; i--)
  171. {
  172. float f; /* Input value. */
  173. float e; /* Exponent of current value. */
  174. f = *in_vec++;
  175. e = QN_EXPQ(f - max);
  176. *out_vec++ = e;
  177. sumexp += e;
  178. }
  179. scale = 1.0f/sumexp;
  180. for (i=0; i<n; i++)
  181. {
  182. *out_vec2 = (*out_vec2) * scale;
  183. out_vec2++;
  184. }
  185. }
  186. #ifdef QN_HAVE_LIBMASS
  187. void
  188. qn_ms_softmax_vf_vf(size_t n, const float* in_vec, float* out_vec)
  189. {
  190. float max;
  191. float min;
  192. float sumexp = 0.0f; /* Sum of exponents */
  193. float scale; /* 1/sum of exponents */
  194. size_t i;
  195. float* outp;
  196. int count = n;
  197. qn_maxmin_vf_ff(n, in_vec, &max, &min); /* Find constant bias. */
  198. outp = out_vec;
  199. for (i=n; i!=0; i--)
  200. {
  201. *outp++ = *in_vec++ - max;
  202. }
  203. vsexp(out_vec, out_vec, &count);
  204. outp = out_vec;
  205. for (i=n; i!=0; i--)
  206. {
  207. sumexp += (*outp++);
  208. }
  209. scale = 1.0f/sumexp;
  210. outp = out_vec;
  211. for (i=n; i!=0; i--)
  212. {
  213. *outp = (*outp) * scale;
  214. outp++;
  215. }
  216. }
  217. #endif
  218. void
  219. qn_htopre8_vf_vi8(size_t len, const float* from, QNInt8* to)
  220. {
  221. size_t i;
  222. for (i=0; i<len; i++)
  223. {
  224. *to++ = qn_htopre8_f_i8(*from++);
  225. }
  226. }
  227. void
  228. qn_pre8toh_vi8_vf(size_t len, const QNInt8* bits, float* res)
  229. {
  230. float* table; /* Pointer to the start of the lookup table */
  231. size_t i; /* Local counter */
  232. table = qn_pre8table_vf(); /* Point to the table for converting pre8
  233. bytes to floating point */
  234. for (i=0; i<len; i++)
  235. {
  236. *res++ = table[(QNUInt8) *bits++];
  237. }
  238. }
  239. void
  240. qn_lna8toh_vi8_vf(size_t len, const QNInt8* bits, float* res)
  241. {
  242. float* table; /* Pointer to the start of the lookup table */
  243. size_t i; /* Local counter */
  244. table = qn_lna8table_vf(); /* Point to the table for converting lna8
  245. bytes to floating point */
  246. for (i=0; i<len; i++)
  247. {
  248. *res++ = table[(QNUInt8) *bits++];
  249. }
  250. }
  251. void
  252. qn_htolna8_vf_vi8(size_t len, const float* from, QNInt8* to)
  253. {
  254. size_t i;
  255. for (i=0; i<len; i++)
  256. {
  257. *to++ = qn_htolna8_f_i8(*from++);
  258. }
  259. }
  260. size_t
  261. qn_imax_vf_u(size_t n, const float* v)
  262. {
  263. float best_val = *v++;
  264. size_t index = 0;
  265. int nan = (int) qn_isnan_f_b(best_val); /* 1 if we have seen a nan */
  266. size_t i;
  267. assert(n>0);
  268. for (i=1; i<n; i++)
  269. {
  270. const float val = *v++;
  271. nan |= qn_isnan_f_b(val);
  272. if (val>best_val)
  273. {
  274. best_val = val;
  275. index = i;
  276. }
  277. }
  278. if (nan)
  279. return(QN_SIZET_BAD);
  280. else
  281. return index;
  282. }
  283. float*
  284. qn_pre8table_vf(void)
  285. {
  286. enum { TABLEN = 256 };
  287. static float table[TABLEN];
  288. static int init = 0;
  289. /* If the tables not build, then build it */
  290. if (!init)
  291. {
  292. size_t i;
  293. init = 1;
  294. /* Fill in the values in the table */
  295. for (i = 0; i<TABLEN; i++)
  296. table[i] = QN_SQRT2 * qn_ierf_f_f(2.0 * (i + 0.5) / TABLEN - 1.0);
  297. }
  298. return &table[0];
  299. }
  300. float*
  301. qn_lna8table_vf(void)
  302. {
  303. enum { TABLEN = 256 };
  304. static float table[TABLEN];
  305. static int init = 0;
  306. /* If the table is not built, then build it */
  307. if (!init)
  308. {
  309. size_t i;
  310. init = 1;
  311. /* Fill in the values in the table */
  312. for (i = 0; i<TABLEN; i++)
  313. table[i] = exp(-((double) i + 0.5) / QN_LNA8_SCALE);
  314. }
  315. return &table[0];
  316. }
  317. void
  318. qn_copy_svf_vf(size_t len, size_t stride, const float* in, float* out)
  319. {
  320. const float* from = in;
  321. float* to = out;
  322. while(len--)
  323. {
  324. *to = *from;
  325. to++;
  326. from += stride;
  327. }
  328. }
  329. void
  330. qn_nv_copy_vf_mf(size_t mat_height, size_t vec_len, const float* vec, float* mat)
  331. {
  332. size_t i, j;
  333. const float* vec_ptr;
  334. float* mat_ptr = mat;
  335. for (i=mat_height; i!=0; i--)
  336. {
  337. vec_ptr = vec;
  338. for (j=vec_len; j!=0; j--)
  339. {
  340. (*mat_ptr++) = (*vec_ptr++);
  341. }
  342. }
  343. }
  344. void
  345. qn_pp_copy_vf_mf(size_t mat_height, size_t vec_len, const float* vec, float* mat)
  346. {
  347. size_t i;
  348. const float* vec_ptr;
  349. float* mat_ptr = mat;
  350. for (i=mat_height; i!=0; i--)
  351. {
  352. vec_ptr = vec;
  353. memcpy((void*) mat_ptr, (void*) vec, vec_len);
  354. mat_ptr += vec_len;
  355. }
  356. }
  357. float
  358. qn_nv_mulsum_vfvf_f(const size_t n, const float* avec, const float* bvec)
  359. {
  360. register float sum = 0.0f;
  361. size_t i;
  362. for (i=0; i<n; i++)
  363. sum += avec[i] * bvec[i];
  364. return sum;
  365. }
  366. // Sum the columns of a matrix into a vector.
  367. // This is a hand-optimized version that should be faster than more
  368. // straightforward code.
  369. void
  370. qn_sumcol_mf_vf(size_t rows, size_t cols, const float* in, float* res)
  371. {
  372. const float *const res_end_b8p = res + (cols & ~7);
  373. const float *const res_end_p = res + cols;
  374. float* res_p;
  375. const float* in_p = in;
  376. size_t i;
  377. /* Initialize the result */
  378. res_p = res;
  379. while(res_p != res_end_b8p)
  380. {
  381. res_p[0] = in_p[0];
  382. res_p[1] = in_p[1];
  383. res_p[2] = in_p[2];
  384. res_p[3] = in_p[3];
  385. res_p[4] = in_p[4];
  386. res_p[5] = in_p[5];
  387. res_p[6] = in_p[6];
  388. res_p[7] = in_p[7];
  389. res_p += 8;
  390. in_p += 8;
  391. }
  392. while (res_p != res_end_p)
  393. {
  394. (*res_p++) = (*in_p++);
  395. }
  396. /* The main loop */
  397. for (i=1; i!=rows; i++)
  398. {
  399. res_p = res;
  400. while(res_p != res_end_b8p)
  401. {
  402. res_p[0] += in_p[0];
  403. res_p[1] += in_p[1];
  404. res_p[2] += in_p[2];
  405. res_p[3] += in_p[3];
  406. res_p[4] += in_p[4];
  407. res_p[5] += in_p[5];
  408. res_p[6] += in_p[6];
  409. res_p[7] += in_p[7];
  410. res_p += 8;
  411. in_p += 8;
  412. }
  413. while (res_p != res_end_p)
  414. {
  415. (*res_p++) += (*in_p++);
  416. }
  417. }
  418. }
  419. void
  420. qn_copy_mf_smf(size_t height, size_t in_width, size_t stride,
  421. const float* from, float* to)
  422. {
  423. size_t i;
  424. for (i=0; i<height; i++)
  425. {
  426. qn_copy_vf_vf(in_width, from, to);
  427. from += in_width;
  428. to += stride;
  429. }
  430. }
  431. void
  432. qn_copy_smf_mf(size_t height, size_t width, size_t stride,
  433. const float* from, float* to)
  434. {
  435. size_t i;
  436. for (i=0; i<height; i++)
  437. {
  438. qn_copy_vf_vf(width, from, to);
  439. from += stride;
  440. to += width;
  441. }
  442. }
  443. void
  444. qn_trans_mf_mf(size_t in_height, size_t in_width, const float *in, float *res)
  445. {
  446. size_t i, j;
  447. const float *from; /* Get elements from here */
  448. float *to; /* Put elements here */
  449. float *tocol; /* Current column in result */
  450. from = in;
  451. to = res;
  452. tocol = res;
  453. for (i=0; i<in_height; i++)
  454. {
  455. to = tocol;
  456. for (j=0; j<in_width; j++)
  457. {
  458. *to = *from;
  459. from++;
  460. to += in_height;
  461. }
  462. tocol++;
  463. }
  464. }
  465. // Some naive routines that have blas or pp versions elsewhere
  466. void
  467. qn_nv_mul_mfvf_vf(const size_t rows, const size_t cols,
  468. const float *in_mat, const float *in_vec, float *out_vec)
  469. {
  470. size_t i;
  471. size_t j;
  472. for (i=0; i<rows; i++)
  473. {
  474. float sum = 0.0;
  475. const float *inp = in_vec;
  476. for (j=0; j<cols; j++)
  477. {
  478. sum += (*in_mat++) * (*inp++);
  479. }
  480. *out_vec++ = sum;
  481. }
  482. }
  483. void
  484. qn_nv_mul_vfmf_vf(const size_t rows, const size_t cols,
  485. const float *in_vec, const float *in_mat, float *out_vec)
  486. {
  487. size_t i;
  488. size_t j;
  489. for (i=0; i<cols; i++)
  490. {
  491. float sum = 0.0;
  492. const float *vp = in_vec;
  493. const float *mp = in_mat + i;
  494. for (j=0; j<rows; j++)
  495. {
  496. sum += (*mp) * (*vp++);
  497. mp += cols;
  498. }
  499. *out_vec++ = sum;
  500. }
  501. }
  502. void
  503. qn_nv_mulacc_fvfvf_mf(const size_t rows, const size_t cols,
  504. const float scale,
  505. const float *in_vec, const float *in_vec_t,
  506. float *res_mat)
  507. {
  508. size_t i;
  509. size_t j;
  510. for (i=0; i<rows; i++)
  511. {
  512. const float row_val = in_vec[i] * scale;
  513. const float *vtp = in_vec_t;
  514. for (j=0; j<cols; j++)
  515. {
  516. *res_mat++ += vtp[j] * row_val;
  517. }
  518. }
  519. }
  520. void
  521. qn_nv_mulacc_fmfmf_mf(size_t Sm,size_t Sk,size_t Sn, float scale,
  522. const float *A,const float *B,float *C)
  523. {
  524. size_t i,j,k;
  525. float acc;
  526. for (i=0;i<Sm;i++)
  527. {
  528. for (j=0;j<Sn;j++)
  529. {
  530. acc = 0.0f;
  531. for (k=0;k<Sk;k++)
  532. acc += A[i*Sk+k]*B[k*Sn+j];
  533. C[i*Sn+j] += acc * scale;
  534. }
  535. }
  536. }
  537. void
  538. qn_nv_mulntacc_mfmf_mf(size_t Sm,size_t Sk,size_t Sn,
  539. const float *A,const float *B,float *C)
  540. {
  541. size_t i,j,k;
  542. for (i=0;i<Sm;i++)
  543. for (j=0;j<Sn;j++)
  544. for (k=0;k<Sk;k++)
  545. C[i*Sn+j] += A[i*Sk+k]*B[j*Sk+k];
  546. }
  547. void
  548. qn_nv_multnacc_fmfmf_mf(size_t Sk,size_t Sm,size_t Sn, float scale,
  549. const float *A,const float *B,float *C)
  550. {
  551. size_t i,j,k;
  552. float acc;
  553. for (i=0;i<Sm;i++)
  554. {
  555. for (j=0;j<Sn;j++)
  556. {
  557. acc = 0.0f;
  558. for (k=0;k<Sk;k++)
  559. acc += A[k*Sm+i]*B[k*Sn+j];
  560. C[i*Sn+j] += acc * scale;
  561. }
  562. }
  563. }
  564. void
  565. qn_nv_mulacc_mfmf_mf(size_t Sm,size_t Sk,size_t Sn,
  566. const float *A,const float *B,float *C)
  567. {
  568. size_t i,j,k;
  569. for (i=0;i<Sm;i++)
  570. for (j=0;j<Sn;j++)
  571. for (k=0;k<Sk;k++)
  572. C[i*Sn+j] += A[i*Sk+k]*B[k*Sn+j];
  573. }
  574. void
  575. qn_nv_mul_mfmf_mf(size_t Sm,size_t Sk,size_t Sn,
  576. const float *A,const float *B,float *C)
  577. {
  578. size_t i,j,k;
  579. for (i=0;i<Sm;i++)
  580. {
  581. for (j=0;j<Sn;j++)
  582. {
  583. C[i*Sn+j] = 0.0f;
  584. for (k=0;k<Sk;k++)
  585. C[i*Sn+j] += A[i*Sk+k]*B[k*Sn+j];
  586. }
  587. }
  588. }
  589. void
  590. qn_nv_convol_vfvf_vf(size_t h_len, size_t x_len, const float *h,
  591. const float *x, float *y)
  592. {
  593. size_t i;
  594. const float *x_startp = x + h_len - 1;
  595. const float *x_endp = x - 1;
  596. for( i = 0; i != x_len - h_len + 1; i++ ) {
  597. float y_acc = 0.0;
  598. const float *hp = h;
  599. const float *xp;
  600. for( xp = x_startp; xp != x_endp; xp-- ) {
  601. y_acc += *xp * *hp;
  602. hp++;
  603. }
  604. *y++ = y_acc;
  605. x_startp++;
  606. x_endp++;
  607. }
  608. }
  609. size_t
  610. qn_fread_Of_vf(size_t count, FILE* file, float* f)
  611. {
  612. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(*f) };
  613. float buf[bufsize];
  614. size_t rc = 0;
  615. size_t chunk = 0;
  616. size_t res = 0;
  617. while (count > 0 && rc == chunk)
  618. {
  619. chunk = qn_min_zz_z(bufsize, count);
  620. rc = fread(buf, sizeof(*f), chunk, file);
  621. qn_swapb_vf_vf(rc, buf, f);
  622. count -= rc;
  623. res += rc;
  624. f += rc;
  625. }
  626. return res;
  627. }
  628. size_t
  629. qn_fread_Od_vd(size_t count, FILE* file, double* d)
  630. {
  631. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(*d) };
  632. double buf[bufsize];
  633. size_t rc = 0;
  634. size_t chunk = 0;
  635. size_t res = 0;
  636. while (count > 0 && rc == chunk)
  637. {
  638. chunk = qn_min_zz_z(bufsize, count);
  639. rc = fread(buf, sizeof(*d), chunk, file);
  640. qn_swapb_vd_vd(rc, buf, d);
  641. count -= rc;
  642. res += rc;
  643. d += rc;
  644. }
  645. return res;
  646. }
  647. size_t
  648. qn_fread_Od_vf(size_t count, FILE* file, float* f)
  649. {
  650. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(double) };
  651. double buf[bufsize];
  652. double buf2[bufsize];
  653. size_t rc = 0;
  654. size_t chunk = 0;
  655. size_t res = 0;
  656. while (count > 0 && rc == chunk)
  657. {
  658. chunk = qn_min_zz_z(bufsize, count);
  659. rc = fread(buf, sizeof(double), chunk, file);
  660. qn_swapb_vd_vd(rc, buf, buf2);
  661. qn_conv_vd_vf(rc, buf2, f);
  662. count -= rc;
  663. res += rc;
  664. f += rc;
  665. }
  666. return res;
  667. }
  668. size_t
  669. qn_fread_Of_vd(size_t count, FILE* file, double* d)
  670. {
  671. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(float) };
  672. float buf[bufsize];
  673. float buf2[bufsize];
  674. size_t rc = 0;
  675. size_t chunk = 0;
  676. size_t res = 0;
  677. while (count > 0 && rc == chunk)
  678. {
  679. chunk = qn_min_zz_z(bufsize, count);
  680. rc = fread(buf, sizeof(float), chunk, file);
  681. qn_swapb_vf_vf(rc, buf, buf2);
  682. qn_conv_vf_vd(rc, buf2, d);
  683. count -= rc;
  684. res += rc;
  685. d += rc;
  686. }
  687. return res;
  688. }
  689. size_t
  690. qn_fread_Nf_vd(size_t count, FILE* file, double* d)
  691. {
  692. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(float) };
  693. float buf[bufsize];
  694. size_t rc = 0;
  695. size_t chunk = 0;
  696. size_t res = 0;
  697. while (count > 0 && rc == chunk)
  698. {
  699. chunk = qn_min_zz_z(bufsize, count);
  700. rc = fread(buf, sizeof(float), chunk, file);
  701. qn_conv_vf_vd(rc, buf, d);
  702. count -= rc;
  703. res += rc;
  704. d += rc;
  705. }
  706. return res;
  707. }
  708. size_t
  709. qn_fread_Nd_vf(size_t count, FILE* file, float* f)
  710. {
  711. enum { bufsize = QN_FREAD_DEF_BUFSIZE/sizeof(float) };
  712. double buf[bufsize];
  713. size_t rc = 0;
  714. size_t chunk = 0;
  715. size_t res = 0;
  716. while (count > 0 && rc == chunk)
  717. {
  718. chunk = qn_min_zz_z(bufsize, count);
  719. rc = fread(buf, sizeof(double), chunk, file);
  720. qn_conv_vd_vf(rc, buf, f);
  721. count -= rc;
  722. res += rc;
  723. f += rc;
  724. }
  725. return res;
  726. }