File indexing completed on 2024-05-05 17:33:22
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Jonathan Thomas <echidnaman@kubuntu.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "Rating.h" 0008 #include "libdiscover_debug.h" 0009 #include <QStringList> 0010 #include <qmath.h> 0011 0012 inline double fastPow(double a, double b) 0013 { 0014 union { 0015 double d; 0016 int x[2]; 0017 } u = {a}; 0018 0019 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 0020 u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447); 0021 u.x[0] = 0; 0022 #else 0023 u.x[1] = 0; 0024 u.x[0] = (int)(b * (u.x[1] - 1072632447) + 1072632447); 0025 #endif 0026 0027 return u.d; 0028 } 0029 0030 // Converted from a Ruby example, returns an inverse normal distribution 0031 double pnormaldist(double qn) 0032 { 0033 double b[] = {1.570796288, 0034 0.03706987906, 0035 -0.8364353589e-3, 0036 -0.2250947176e-3, 0037 0.6841218299e-5, 0038 0.5824238515e-5, 0039 -0.104527497e-5, 0040 0.8360937017e-7, 0041 -0.3231081277e-8, 0042 0.3657763036e-10, 0043 0.6936233982e-12}; 0044 0045 if (qn < 0.0 || 1.0 < qn) 0046 return 0.0; 0047 0048 if (qn == 0.5) 0049 return 0.0; 0050 0051 double w1 = qn; 0052 if (qn > 0.5) 0053 w1 = 1.0 - w1; 0054 double w3 = -qLn(4.0 * w1 * (1.0 - w1)); 0055 w1 = b[0]; 0056 0057 for (int i = 1; i < 11; i++) 0058 w1 += b[i] * fastPow(w3, i); 0059 0060 if (qn > 0.5) 0061 return qSqrt(w1 * w3); 0062 return -qSqrt(w1 * w3); 0063 } 0064 0065 double wilson_score(int pos, int n, double power = 0.2) 0066 { 0067 if (n == 0) 0068 return 0; 0069 0070 double z = pnormaldist(1 - power / 2); 0071 double phat = 1.0 * pos / n; 0072 return (phat + z * z / (2 * n) - z * qSqrt((phat * (1 - phat) + z * z / (4 * n)) / n)) / (1 + z * z / n); 0073 } 0074 0075 double dampenedRating(int ratings[6], double power = 0.1) 0076 { 0077 int tot_ratings = 0; 0078 for (int i = 0; i < 6; ++i) 0079 tot_ratings = ratings[i] + tot_ratings; 0080 0081 double sum_scores = 0.0; 0082 for (int i = 0; i < 6; i++) { 0083 const int rating = ratings[i]; 0084 double ws = wilson_score(rating, tot_ratings, power); 0085 sum_scores = sum_scores + float((i + 1) - 3) * ws; 0086 } 0087 0088 return sum_scores + 3; 0089 } 0090 0091 Rating::Rating(const QString &packageName, quint64 ratingCount, int data[6]) 0092 : m_packageName(packageName) 0093 , m_ratingCount(ratingCount) 0094 // TODO consider storing data[] and present in UI 0095 , m_rating(((data[1] // 0096 + (data[2] * 2) // 0097 + (data[3] * 3) // 0098 + (data[4] * 4) // 0099 + (data[5] * 5)) // 0100 * 2) 0101 / qMax<float>(1, ratingCount)) 0102 , m_ratingPoints(0) 0103 , m_sortableRating(0) 0104 { 0105 int spread[6]; 0106 for (int i = 0; i < 6; ++i) { 0107 int points = data[i]; 0108 m_ratingPoints += (i + 1) * points; 0109 spread[i] = points; 0110 } 0111 0112 m_sortableRating = dampenedRating(spread) * 2; 0113 } 0114 0115 Rating::Rating(const QString &packageName, quint64 ratingCount, int rating) 0116 : m_packageName(packageName) 0117 , m_ratingCount(ratingCount) 0118 , m_rating(rating) 0119 , m_ratingPoints(rating) 0120 , m_sortableRating(rating) 0121 { 0122 } 0123 0124 Rating::~Rating() = default; 0125 0126 QString Rating::packageName() const 0127 { 0128 return m_packageName; 0129 } 0130 0131 quint64 Rating::ratingCount() const 0132 { 0133 return m_ratingCount; 0134 } 0135 0136 float Rating::rating() const 0137 { 0138 return m_rating; 0139 } 0140 0141 int Rating::ratingPoints() const 0142 { 0143 return m_ratingPoints; 0144 } 0145 0146 double Rating::sortableRating() const 0147 { 0148 return m_sortableRating; 0149 }