floats.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. // Copyright ©2013 The Gonum Authors. All rights reserved.
  2. // Use of this code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package floats
  5. import (
  6. "errors"
  7. "math"
  8. "sort"
  9. "gonum.org/v1/gonum/floats/scalar"
  10. "gonum.org/v1/gonum/internal/asm/f64"
  11. )
  12. const (
  13. zeroLength = "floats: zero length slice"
  14. shortSpan = "floats: slice length less than 2"
  15. badLength = "floats: slice lengths do not match"
  16. badDstLength = "floats: destination slice length does not match input"
  17. )
  18. // Add adds, element-wise, the elements of s and dst, and stores the result in dst.
  19. // It panics if the argument lengths do not match.
  20. func Add(dst, s []float64) {
  21. if len(dst) != len(s) {
  22. panic(badDstLength)
  23. }
  24. f64.AxpyUnitaryTo(dst, 1, s, dst)
  25. }
  26. // AddTo adds, element-wise, the elements of s and t and
  27. // stores the result in dst.
  28. // It panics if the argument lengths do not match.
  29. func AddTo(dst, s, t []float64) []float64 {
  30. if len(s) != len(t) {
  31. panic(badLength)
  32. }
  33. if len(dst) != len(s) {
  34. panic(badDstLength)
  35. }
  36. f64.AxpyUnitaryTo(dst, 1, s, t)
  37. return dst
  38. }
  39. // AddConst adds the scalar c to all of the values in dst.
  40. func AddConst(c float64, dst []float64) {
  41. f64.AddConst(c, dst)
  42. }
  43. // AddScaled performs dst = dst + alpha * s.
  44. // It panics if the slice argument lengths do not match.
  45. func AddScaled(dst []float64, alpha float64, s []float64) {
  46. if len(dst) != len(s) {
  47. panic(badLength)
  48. }
  49. f64.AxpyUnitaryTo(dst, alpha, s, dst)
  50. }
  51. // AddScaledTo performs dst = y + alpha * s, where alpha is a scalar,
  52. // and dst, y and s are all slices.
  53. // It panics if the slice argument lengths do not match.
  54. //
  55. // At the return of the function, dst[i] = y[i] + alpha * s[i]
  56. func AddScaledTo(dst, y []float64, alpha float64, s []float64) []float64 {
  57. if len(s) != len(y) {
  58. panic(badLength)
  59. }
  60. if len(dst) != len(y) {
  61. panic(badDstLength)
  62. }
  63. f64.AxpyUnitaryTo(dst, alpha, s, y)
  64. return dst
  65. }
  66. // argsort is a helper that implements sort.Interface, as used by
  67. // Argsort.
  68. type argsort struct {
  69. s []float64
  70. inds []int
  71. }
  72. func (a argsort) Len() int {
  73. return len(a.s)
  74. }
  75. func (a argsort) Less(i, j int) bool {
  76. return a.s[i] < a.s[j]
  77. }
  78. func (a argsort) Swap(i, j int) {
  79. a.s[i], a.s[j] = a.s[j], a.s[i]
  80. a.inds[i], a.inds[j] = a.inds[j], a.inds[i]
  81. }
  82. // Argsort sorts the elements of dst while tracking their original order.
  83. // At the conclusion of Argsort, dst will contain the original elements of dst
  84. // but sorted in increasing order, and inds will contain the original position
  85. // of the elements in the slice such that dst[i] = origDst[inds[i]].
  86. // It panics if the argument lengths do not match.
  87. func Argsort(dst []float64, inds []int) {
  88. if len(dst) != len(inds) {
  89. panic(badDstLength)
  90. }
  91. for i := range dst {
  92. inds[i] = i
  93. }
  94. a := argsort{s: dst, inds: inds}
  95. sort.Sort(a)
  96. }
  97. // Count applies the function f to every element of s and returns the number
  98. // of times the function returned true.
  99. func Count(f func(float64) bool, s []float64) int {
  100. var n int
  101. for _, val := range s {
  102. if f(val) {
  103. n++
  104. }
  105. }
  106. return n
  107. }
  108. // CumProd finds the cumulative product of the first i elements in
  109. // s and puts them in place into the ith element of the
  110. // destination dst.
  111. // It panics if the argument lengths do not match.
  112. //
  113. // At the return of the function, dst[i] = s[i] * s[i-1] * s[i-2] * ...
  114. func CumProd(dst, s []float64) []float64 {
  115. if len(dst) != len(s) {
  116. panic(badDstLength)
  117. }
  118. if len(dst) == 0 {
  119. return dst
  120. }
  121. return f64.CumProd(dst, s)
  122. }
  123. // CumSum finds the cumulative sum of the first i elements in
  124. // s and puts them in place into the ith element of the
  125. // destination dst.
  126. // It panics if the argument lengths do not match.
  127. //
  128. // At the return of the function, dst[i] = s[i] + s[i-1] + s[i-2] + ...
  129. func CumSum(dst, s []float64) []float64 {
  130. if len(dst) != len(s) {
  131. panic(badDstLength)
  132. }
  133. if len(dst) == 0 {
  134. return dst
  135. }
  136. return f64.CumSum(dst, s)
  137. }
  138. // Distance computes the L-norm of s - t. See Norm for special cases.
  139. // It panics if the slice argument lengths do not match.
  140. func Distance(s, t []float64, L float64) float64 {
  141. if len(s) != len(t) {
  142. panic(badLength)
  143. }
  144. if len(s) == 0 {
  145. return 0
  146. }
  147. if L == 2 {
  148. return f64.L2DistanceUnitary(s, t)
  149. }
  150. var norm float64
  151. if L == 1 {
  152. for i, v := range s {
  153. norm += math.Abs(t[i] - v)
  154. }
  155. return norm
  156. }
  157. if math.IsInf(L, 1) {
  158. for i, v := range s {
  159. absDiff := math.Abs(t[i] - v)
  160. if absDiff > norm {
  161. norm = absDiff
  162. }
  163. }
  164. return norm
  165. }
  166. for i, v := range s {
  167. norm += math.Pow(math.Abs(t[i]-v), L)
  168. }
  169. return math.Pow(norm, 1/L)
  170. }
  171. // Div performs element-wise division dst / s
  172. // and stores the value in dst.
  173. // It panics if the argument lengths do not match.
  174. func Div(dst, s []float64) {
  175. if len(dst) != len(s) {
  176. panic(badLength)
  177. }
  178. f64.Div(dst, s)
  179. }
  180. // DivTo performs element-wise division s / t
  181. // and stores the value in dst.
  182. // It panics if the argument lengths do not match.
  183. func DivTo(dst, s, t []float64) []float64 {
  184. if len(s) != len(t) {
  185. panic(badLength)
  186. }
  187. if len(dst) != len(s) {
  188. panic(badDstLength)
  189. }
  190. return f64.DivTo(dst, s, t)
  191. }
  192. // Dot computes the dot product of s1 and s2, i.e.
  193. // sum_{i = 1}^N s1[i]*s2[i].
  194. // It panics if the argument lengths do not match.
  195. func Dot(s1, s2 []float64) float64 {
  196. if len(s1) != len(s2) {
  197. panic(badLength)
  198. }
  199. return f64.DotUnitary(s1, s2)
  200. }
  201. // Equal returns true when the slices have equal lengths and
  202. // all elements are numerically identical.
  203. func Equal(s1, s2 []float64) bool {
  204. if len(s1) != len(s2) {
  205. return false
  206. }
  207. for i, val := range s1 {
  208. if s2[i] != val {
  209. return false
  210. }
  211. }
  212. return true
  213. }
  214. // EqualApprox returns true when the slices have equal lengths and
  215. // all element pairs have an absolute tolerance less than tol or a
  216. // relative tolerance less than tol.
  217. func EqualApprox(s1, s2 []float64, tol float64) bool {
  218. if len(s1) != len(s2) {
  219. return false
  220. }
  221. for i, a := range s1 {
  222. if !scalar.EqualWithinAbsOrRel(a, s2[i], tol, tol) {
  223. return false
  224. }
  225. }
  226. return true
  227. }
  228. // EqualFunc returns true when the slices have the same lengths
  229. // and the function returns true for all element pairs.
  230. func EqualFunc(s1, s2 []float64, f func(float64, float64) bool) bool {
  231. if len(s1) != len(s2) {
  232. return false
  233. }
  234. for i, val := range s1 {
  235. if !f(val, s2[i]) {
  236. return false
  237. }
  238. }
  239. return true
  240. }
  241. // EqualLengths returns true when all of the slices have equal length,
  242. // and false otherwise. It also returns true when there are no input slices.
  243. func EqualLengths(slices ...[]float64) bool {
  244. // This length check is needed: http://play.golang.org/p/sdty6YiLhM
  245. if len(slices) == 0 {
  246. return true
  247. }
  248. l := len(slices[0])
  249. for i := 1; i < len(slices); i++ {
  250. if len(slices[i]) != l {
  251. return false
  252. }
  253. }
  254. return true
  255. }
  256. // Find applies f to every element of s and returns the indices of the first
  257. // k elements for which the f returns true, or all such elements
  258. // if k < 0.
  259. // Find will reslice inds to have 0 length, and will append
  260. // found indices to inds.
  261. // If k > 0 and there are fewer than k elements in s satisfying f,
  262. // all of the found elements will be returned along with an error.
  263. // At the return of the function, the input inds will be in an undetermined state.
  264. func Find(inds []int, f func(float64) bool, s []float64, k int) ([]int, error) {
  265. // inds is also returned to allow for calling with nil.
  266. // Reslice inds to have zero length.
  267. inds = inds[:0]
  268. // If zero elements requested, can just return.
  269. if k == 0 {
  270. return inds, nil
  271. }
  272. // If k < 0, return all of the found indices.
  273. if k < 0 {
  274. for i, val := range s {
  275. if f(val) {
  276. inds = append(inds, i)
  277. }
  278. }
  279. return inds, nil
  280. }
  281. // Otherwise, find the first k elements.
  282. nFound := 0
  283. for i, val := range s {
  284. if f(val) {
  285. inds = append(inds, i)
  286. nFound++
  287. if nFound == k {
  288. return inds, nil
  289. }
  290. }
  291. }
  292. // Finished iterating over the loop, which means k elements were not found.
  293. return inds, errors.New("floats: insufficient elements found")
  294. }
  295. // HasNaN returns true when the slice s has any values that are NaN and false
  296. // otherwise.
  297. func HasNaN(s []float64) bool {
  298. for _, v := range s {
  299. if math.IsNaN(v) {
  300. return true
  301. }
  302. }
  303. return false
  304. }
  305. // LogSpan returns a set of n equally spaced points in log space between,
  306. // l and u where N is equal to len(dst). The first element of the
  307. // resulting dst will be l and the final element of dst will be u.
  308. // It panics if the length of dst is less than 2.
  309. // Note that this call will return NaNs if either l or u are negative, and
  310. // will return all zeros if l or u is zero.
  311. // Also returns the mutated slice dst, so that it can be used in range, like:
  312. //
  313. // for i, x := range LogSpan(dst, l, u) { ... }
  314. func LogSpan(dst []float64, l, u float64) []float64 {
  315. Span(dst, math.Log(l), math.Log(u))
  316. for i := range dst {
  317. dst[i] = math.Exp(dst[i])
  318. }
  319. return dst
  320. }
  321. // LogSumExp returns the log of the sum of the exponentials of the values in s.
  322. // Panics if s is an empty slice.
  323. func LogSumExp(s []float64) float64 {
  324. // Want to do this in a numerically stable way which avoids
  325. // overflow and underflow
  326. // First, find the maximum value in the slice.
  327. maxval := Max(s)
  328. if math.IsInf(maxval, 0) {
  329. // If it's infinity either way, the logsumexp will be infinity as well
  330. // returning now avoids NaNs
  331. return maxval
  332. }
  333. var lse float64
  334. // Compute the sumexp part
  335. for _, val := range s {
  336. lse += math.Exp(val - maxval)
  337. }
  338. // Take the log and add back on the constant taken out
  339. return math.Log(lse) + maxval
  340. }
  341. // Max returns the maximum value in the input slice. If the slice is empty, Max will panic.
  342. func Max(s []float64) float64 {
  343. return s[MaxIdx(s)]
  344. }
  345. // MaxIdx returns the index of the maximum value in the input slice. If several
  346. // entries have the maximum value, the first such index is returned.
  347. // It panics if s is zero length.
  348. func MaxIdx(s []float64) int {
  349. if len(s) == 0 {
  350. panic(zeroLength)
  351. }
  352. max := math.NaN()
  353. var ind int
  354. for i, v := range s {
  355. if math.IsNaN(v) {
  356. continue
  357. }
  358. if v > max || math.IsNaN(max) {
  359. max = v
  360. ind = i
  361. }
  362. }
  363. return ind
  364. }
  365. // Min returns the minimum value in the input slice.
  366. // It panics if s is zero length.
  367. func Min(s []float64) float64 {
  368. return s[MinIdx(s)]
  369. }
  370. // MinIdx returns the index of the minimum value in the input slice. If several
  371. // entries have the minimum value, the first such index is returned.
  372. // It panics if s is zero length.
  373. func MinIdx(s []float64) int {
  374. if len(s) == 0 {
  375. panic(zeroLength)
  376. }
  377. min := math.NaN()
  378. var ind int
  379. for i, v := range s {
  380. if math.IsNaN(v) {
  381. continue
  382. }
  383. if v < min || math.IsNaN(min) {
  384. min = v
  385. ind = i
  386. }
  387. }
  388. return ind
  389. }
  390. // Mul performs element-wise multiplication between dst
  391. // and s and stores the value in dst.
  392. // It panics if the argument lengths do not match.
  393. func Mul(dst, s []float64) {
  394. if len(dst) != len(s) {
  395. panic(badLength)
  396. }
  397. for i, val := range s {
  398. dst[i] *= val
  399. }
  400. }
  401. // MulTo performs element-wise multiplication between s
  402. // and t and stores the value in dst.
  403. // It panics if the argument lengths do not match.
  404. func MulTo(dst, s, t []float64) []float64 {
  405. if len(s) != len(t) {
  406. panic(badLength)
  407. }
  408. if len(dst) != len(s) {
  409. panic(badDstLength)
  410. }
  411. for i, val := range t {
  412. dst[i] = val * s[i]
  413. }
  414. return dst
  415. }
  416. // NearestIdx returns the index of the element in s
  417. // whose value is nearest to v. If several such
  418. // elements exist, the lowest index is returned.
  419. // It panics if s is zero length.
  420. func NearestIdx(s []float64, v float64) int {
  421. if len(s) == 0 {
  422. panic(zeroLength)
  423. }
  424. switch {
  425. case math.IsNaN(v):
  426. return 0
  427. case math.IsInf(v, 1):
  428. return MaxIdx(s)
  429. case math.IsInf(v, -1):
  430. return MinIdx(s)
  431. }
  432. var ind int
  433. dist := math.NaN()
  434. for i, val := range s {
  435. newDist := math.Abs(v - val)
  436. // A NaN distance will not be closer.
  437. if math.IsNaN(newDist) {
  438. continue
  439. }
  440. if newDist < dist || math.IsNaN(dist) {
  441. dist = newDist
  442. ind = i
  443. }
  444. }
  445. return ind
  446. }
  447. // NearestIdxForSpan return the index of a hypothetical vector created
  448. // by Span with length n and bounds l and u whose value is closest
  449. // to v. That is, NearestIdxForSpan(n, l, u, v) is equivalent to
  450. // Nearest(Span(make([]float64, n),l,u),v) without an allocation.
  451. // It panics if n is less than two.
  452. func NearestIdxForSpan(n int, l, u float64, v float64) int {
  453. if n < 2 {
  454. panic(shortSpan)
  455. }
  456. if math.IsNaN(v) {
  457. return 0
  458. }
  459. // Special cases for Inf and NaN.
  460. switch {
  461. case math.IsNaN(l) && !math.IsNaN(u):
  462. return n - 1
  463. case math.IsNaN(u):
  464. return 0
  465. case math.IsInf(l, 0) && math.IsInf(u, 0):
  466. if l == u {
  467. return 0
  468. }
  469. if n%2 == 1 {
  470. if !math.IsInf(v, 0) {
  471. return n / 2
  472. }
  473. if math.Copysign(1, v) == math.Copysign(1, l) {
  474. return 0
  475. }
  476. return n/2 + 1
  477. }
  478. if math.Copysign(1, v) == math.Copysign(1, l) {
  479. return 0
  480. }
  481. return n / 2
  482. case math.IsInf(l, 0):
  483. if v == l {
  484. return 0
  485. }
  486. return n - 1
  487. case math.IsInf(u, 0):
  488. if v == u {
  489. return n - 1
  490. }
  491. return 0
  492. case math.IsInf(v, -1):
  493. if l <= u {
  494. return 0
  495. }
  496. return n - 1
  497. case math.IsInf(v, 1):
  498. if u <= l {
  499. return 0
  500. }
  501. return n - 1
  502. }
  503. // Special cases for v outside (l, u) and (u, l).
  504. switch {
  505. case l < u:
  506. if v <= l {
  507. return 0
  508. }
  509. if v >= u {
  510. return n - 1
  511. }
  512. case l > u:
  513. if v >= l {
  514. return 0
  515. }
  516. if v <= u {
  517. return n - 1
  518. }
  519. default:
  520. return 0
  521. }
  522. // Can't guarantee anything about exactly halfway between
  523. // because of floating point weirdness.
  524. return int((float64(n)-1)/(u-l)*(v-l) + 0.5)
  525. }
  526. // Norm returns the L norm of the slice S, defined as
  527. // (sum_{i=1}^N s[i]^L)^{1/L}
  528. // Special cases:
  529. // L = math.Inf(1) gives the maximum absolute value.
  530. // Does not correctly compute the zero norm (use Count).
  531. func Norm(s []float64, L float64) float64 {
  532. // Should this complain if L is not positive?
  533. // Should this be done in log space for better numerical stability?
  534. // would be more cost
  535. // maybe only if L is high?
  536. if len(s) == 0 {
  537. return 0
  538. }
  539. if L == 2 {
  540. return f64.L2NormUnitary(s)
  541. }
  542. var norm float64
  543. if L == 1 {
  544. for _, val := range s {
  545. norm += math.Abs(val)
  546. }
  547. return norm
  548. }
  549. if math.IsInf(L, 1) {
  550. for _, val := range s {
  551. norm = math.Max(norm, math.Abs(val))
  552. }
  553. return norm
  554. }
  555. for _, val := range s {
  556. norm += math.Pow(math.Abs(val), L)
  557. }
  558. return math.Pow(norm, 1/L)
  559. }
  560. // Prod returns the product of the elements of the slice.
  561. // Returns 1 if len(s) = 0.
  562. func Prod(s []float64) float64 {
  563. prod := 1.0
  564. for _, val := range s {
  565. prod *= val
  566. }
  567. return prod
  568. }
  569. // Reverse reverses the order of elements in the slice.
  570. func Reverse(s []float64) {
  571. for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
  572. s[i], s[j] = s[j], s[i]
  573. }
  574. }
  575. // Same returns true when the input slices have the same length and all
  576. // elements have the same value with NaN treated as the same.
  577. func Same(s, t []float64) bool {
  578. if len(s) != len(t) {
  579. return false
  580. }
  581. for i, v := range s {
  582. w := t[i]
  583. if v != w && !(math.IsNaN(v) && math.IsNaN(w)) {
  584. return false
  585. }
  586. }
  587. return true
  588. }
  589. // Scale multiplies every element in dst by the scalar c.
  590. func Scale(c float64, dst []float64) {
  591. if len(dst) > 0 {
  592. f64.ScalUnitary(c, dst)
  593. }
  594. }
  595. // ScaleTo multiplies the elements in s by c and stores the result in dst.
  596. // It panics if the slice argument lengths do not match.
  597. func ScaleTo(dst []float64, c float64, s []float64) []float64 {
  598. if len(dst) != len(s) {
  599. panic(badDstLength)
  600. }
  601. if len(dst) > 0 {
  602. f64.ScalUnitaryTo(dst, c, s)
  603. }
  604. return dst
  605. }
  606. // Span returns a set of N equally spaced points between l and u, where N
  607. // is equal to the length of the destination. The first element of the destination
  608. // is l, the final element of the destination is u.
  609. // It panics if the length of dst is less than 2.
  610. //
  611. // Span also returns the mutated slice dst, so that it can be used in range expressions,
  612. // like:
  613. //
  614. // for i, x := range Span(dst, l, u) { ... }
  615. func Span(dst []float64, l, u float64) []float64 {
  616. n := len(dst)
  617. if n < 2 {
  618. panic(shortSpan)
  619. }
  620. // Special cases for Inf and NaN.
  621. switch {
  622. case math.IsNaN(l):
  623. for i := range dst[:len(dst)-1] {
  624. dst[i] = math.NaN()
  625. }
  626. dst[len(dst)-1] = u
  627. return dst
  628. case math.IsNaN(u):
  629. for i := range dst[1:] {
  630. dst[i+1] = math.NaN()
  631. }
  632. dst[0] = l
  633. return dst
  634. case math.IsInf(l, 0) && math.IsInf(u, 0):
  635. for i := range dst[:len(dst)/2] {
  636. dst[i] = l
  637. dst[len(dst)-i-1] = u
  638. }
  639. if len(dst)%2 == 1 {
  640. if l != u {
  641. dst[len(dst)/2] = 0
  642. } else {
  643. dst[len(dst)/2] = l
  644. }
  645. }
  646. return dst
  647. case math.IsInf(l, 0):
  648. for i := range dst[:len(dst)-1] {
  649. dst[i] = l
  650. }
  651. dst[len(dst)-1] = u
  652. return dst
  653. case math.IsInf(u, 0):
  654. for i := range dst[1:] {
  655. dst[i+1] = u
  656. }
  657. dst[0] = l
  658. return dst
  659. }
  660. step := (u - l) / float64(n-1)
  661. for i := range dst {
  662. dst[i] = l + step*float64(i)
  663. }
  664. return dst
  665. }
  666. // Sub subtracts, element-wise, the elements of s from dst.
  667. // It panics if the argument lengths do not match.
  668. func Sub(dst, s []float64) {
  669. if len(dst) != len(s) {
  670. panic(badLength)
  671. }
  672. f64.AxpyUnitaryTo(dst, -1, s, dst)
  673. }
  674. // SubTo subtracts, element-wise, the elements of t from s and
  675. // stores the result in dst.
  676. // It panics if the argument lengths do not match.
  677. func SubTo(dst, s, t []float64) []float64 {
  678. if len(s) != len(t) {
  679. panic(badLength)
  680. }
  681. if len(dst) != len(s) {
  682. panic(badDstLength)
  683. }
  684. f64.AxpyUnitaryTo(dst, -1, t, s)
  685. return dst
  686. }
  687. // Sum returns the sum of the elements of the slice.
  688. func Sum(s []float64) float64 {
  689. return f64.Sum(s)
  690. }
  691. // Within returns the first index i where s[i] <= v < s[i+1]. Within panics if:
  692. // - len(s) < 2
  693. // - s is not sorted
  694. func Within(s []float64, v float64) int {
  695. if len(s) < 2 {
  696. panic(shortSpan)
  697. }
  698. if !sort.Float64sAreSorted(s) {
  699. panic("floats: input slice not sorted")
  700. }
  701. if v < s[0] || v >= s[len(s)-1] || math.IsNaN(v) {
  702. return -1
  703. }
  704. for i, f := range s[1:] {
  705. if v < f {
  706. return i
  707. }
  708. }
  709. return -1
  710. }
  711. // SumCompensated returns the sum of the elements of the slice calculated with greater
  712. // accuracy than Sum at the expense of additional computation.
  713. func SumCompensated(s []float64) float64 {
  714. // SumCompensated uses an improved version of Kahan's compensated
  715. // summation algorithm proposed by Neumaier.
  716. // See https://en.wikipedia.org/wiki/Kahan_summation_algorithm for details.
  717. var sum, c float64
  718. for _, x := range s {
  719. // This type conversion is here to prevent a sufficiently smart compiler
  720. // from optimising away these operations.
  721. t := float64(sum + x)
  722. if math.Abs(sum) >= math.Abs(x) {
  723. c += (sum - t) + x
  724. } else {
  725. c += (x - t) + sum
  726. }
  727. sum = t
  728. }
  729. return sum + c
  730. }