sellerator.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <math.h>
  7. #define max(a,b) ({ \
  8. __typeof__ (a) _a = (a); \
  9. __typeof__ (b) _b = (b); \
  10. _a > _b ? _a : _b; \
  11. })
  12. void usage(FILE *out, const char *name) {
  13. fprintf(out, "Usage: %s n p\n", name);
  14. fprintf(out, "\n n: Number of reviews\n p: Percent positive\n");
  15. }
  16. double wilson_lower(long n, double p) {
  17. // https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval#Wilson_score_interval_with_continuity_correction
  18. double z = 1.96; // Let's use a good ol' 95% CI
  19. double w = (2.0*n*p + pow(z,2) - (1.0 + z*sqrt(pow(z,2)-1.0/n+4*n*p*(1-p)+(4*p-2))))
  20. /(2.0*((double)n+pow(z,2)));
  21. return(max(0.0, w));
  22. }
  23. int score(int argc, char **argv) {
  24. if(argc != 3) {
  25. usage(stderr, argv[0]);
  26. exit(1);
  27. }
  28. long n = 0;
  29. char *endptr = NULL;
  30. errno = 0;
  31. n = strtol(argv[1], &endptr, 10);
  32. if(errno != 0) {
  33. fprintf(stderr, "While parsing '%s', got error %d: %s\n", argv[1], errno, strerror(errno));
  34. usage(stderr, argv[0]);
  35. exit(1);
  36. }
  37. if(*endptr != '\0') {
  38. fprintf(stderr, "Error: '%s' is not numeric.\n", argv[1]);
  39. usage(stderr, argv[0]);
  40. exit(1);
  41. }
  42. if(n <= 0) {
  43. fprintf(stderr, "Error: got a non-positive number of reviews: %ld.\n", n);
  44. usage(stderr, argv[0]);
  45. exit(1);
  46. }
  47. double p = 0;
  48. endptr = NULL;
  49. errno = 0;
  50. p = strtod(argv[2], &endptr);
  51. if(errno != 0) {
  52. fprintf(stderr, "While parsing '%s', got error %d: %s\n", argv[1], errno, strerror(errno));
  53. usage(stderr, argv[0]);
  54. exit(1);
  55. }
  56. if(*endptr != '\0') {
  57. fprintf(stderr, "Error: '%s' is not numeric.\n", argv[2]);
  58. usage(stderr, argv[0]);
  59. exit(1);
  60. }
  61. if(p < 0 || p > 100) {
  62. fprintf(stderr, "Got a percentage of %0.1f, which is not between 0.0%% and 100.0%%\n", p);
  63. usage(stderr, argv[0]);
  64. exit(1);
  65. }
  66. double lower = wilson_lower(n, p/100.0);
  67. printf("%f\n", 1.0/(1.0-lower));
  68. return 0;
  69. }
  70. int main(int argc, char **argv) {
  71. if(argc < 2) {
  72. usage(stderr, argv[0]);
  73. exit(1);
  74. }
  75. score(argc, argv);
  76. // TODO: add another subcommand for testing hypothesis of difference between sellers
  77. return 0;
  78. }