LCOV - code coverage report
Current view: top level - src/grpp - grpp_binomial.c (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 31 34 91.2 %
Date: 2025-03-09 07:56:22 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*----------------------------------------------------------------------------*/
       2             : /*  CP2K: A general program to perform molecular dynamics simulations         */
       3             : /*  Copyright 2000-2025 CP2K developers group <https://cp2k.org>              */
       4             : /*                                                                            */
       5             : /*  SPDX-License-Identifier: MIT                                              */
       6             : /*----------------------------------------------------------------------------*/
       7             : 
       8             : /*
       9             :  *  libgrpp - a library for the evaluation of integrals over
      10             :  *            generalized relativistic pseudopotentials.
      11             :  *
      12             :  *  Copyright (C) 2021-2023 Alexander Oleynichenko
      13             :  */
      14             : 
      15             : #include "grpp_binomial.h"
      16             : 
      17             : #include <stdint.h>
      18             : 
      19             : /* The code is borrowed from RosettaCode:
      20             :  * https://rosettacode.org/wiki/Evaluate_binomial_coefficients#C
      21             :  * We go to some effort to handle overflow situations.
      22             :  */
      23             : 
      24             : static uint64_t gcd_ui(uint64_t x, uint64_t y);
      25             : 
      26             : /*
      27             :  * returns binomial coefficient:
      28             :  * ( n )
      29             :  * ( k )
      30             :  */
      31   171874909 : uint64_t libgrpp_binomial(uint64_t n, uint64_t k) {
      32   171874909 :   uint64_t d, g, r = 1;
      33             : 
      34   171874909 :   if (k == 0) {
      35             :     return 1;
      36             :   }
      37   131251759 :   if (k == 1) {
      38             :     return n;
      39             :   }
      40   110357799 :   if (k >= n) {
      41    50880212 :     return (k == n);
      42             :   }
      43    59477587 :   if (k > n / 2) {
      44    28894895 :     k = n - k;
      45             :   }
      46   280864964 :   for (d = 1; d <= k; d++) {
      47   224355405 :     if (r >= UINT64_MAX / n) { /* Possible overflow */
      48     2968028 :       uint64_t nr, dr;         /* reduced numerator / denominator */
      49     2968028 :       g = gcd_ui(n, d);
      50     2968028 :       nr = n / g;
      51     2968028 :       dr = d / g;
      52     2968028 :       g = gcd_ui(r, dr);
      53     2968028 :       r = r / g;
      54     2968028 :       dr = dr / g;
      55     2968028 :       if (r >= UINT64_MAX / nr)
      56             :         return 0; /* Unavoidable overflow */
      57           0 :       r *= nr;
      58           0 :       r /= dr;
      59           0 :       n--;
      60             :     } else {
      61   221387377 :       r *= n--;
      62   221387377 :       r /= d;
      63             :     }
      64             :   }
      65             :   return r;
      66             : }
      67             : 
      68     5936056 : static uint64_t gcd_ui(uint64_t x, uint64_t y) {
      69     5936056 :   uint64_t t;
      70             : 
      71     5936056 :   if (y < x) {
      72     2968028 :     t = x;
      73     2968028 :     x = y;
      74     2968028 :     y = t;
      75             :   }
      76    14840140 :   while (y > 0) {
      77     8904084 :     t = y;
      78     8904084 :     y = x % y;
      79     8904084 :     x = t; /* y1 <- x0 % y0 ; x1 <- y0 */
      80             :   }
      81     5936056 :   return x;
      82             : }

Generated by: LCOV version 1.15