mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Introduce new rounding function to StatisticsUtil
It is far less optimal than roundToPowerOfTwo, but allows to have more precision values when needed. (cherry picked from commit 21c001ec375b2be1df5feef4695bd7390db7b62f) IJ-CR-12365 GitOrigin-RevId: 9b5507cb00db48e844d289d2f90e09abce58a373
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bc72ce8bab
commit
3a0d98a9d6
+90
-1
@@ -7,6 +7,7 @@ import com.intellij.internal.statistic.eventLog.EventLogConfiguration
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil.getCurrentHourInUTC
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil.getNextPowerOfTwo
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil.roundToHighestDigit
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil.roundToPowerOfTwo
|
||||
import com.intellij.internal.statistic.utils.StatisticsUtil.roundToUpperBound
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
@@ -120,6 +121,94 @@ class StatisticsUtilTest : LightPlatformTestCase() {
|
||||
assertEquals(expected, roundToPowerOfTwo(value), "Incorrect key for value `$value`")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test round to highest digit int`() {
|
||||
// Test from -10..10
|
||||
for (i in -10..-5) {
|
||||
testRoundToHighestDigit(i, -10)
|
||||
}
|
||||
for (i in -4..-1) {
|
||||
testRoundToHighestDigit(i, -1)
|
||||
}
|
||||
testRoundToHighestDigit(0, 0)
|
||||
for (i in 1..4) {
|
||||
testRoundToHighestDigit(i, 1)
|
||||
}
|
||||
for (i in 5..10) {
|
||||
testRoundToHighestDigit(i, 10)
|
||||
}
|
||||
|
||||
testRoundToHighestDigit(11, 10)
|
||||
testRoundToHighestDigit(16, 20)
|
||||
testRoundToHighestDigit(64, 60)
|
||||
testRoundToHighestDigit(65, 70)
|
||||
|
||||
testRoundToHighestDigit(94, 90)
|
||||
testRoundToHighestDigit(95, 100)
|
||||
testRoundToHighestDigit(99, 100)
|
||||
|
||||
for (i in 1..9) {
|
||||
val expected = i * 1000
|
||||
testRoundToHighestDigit(expected, expected)
|
||||
}
|
||||
|
||||
testRoundToHighestDigit(1024, 1000)
|
||||
testRoundToHighestDigit(1500, 2000)
|
||||
testRoundToHighestDigit(1999, 2000)
|
||||
|
||||
testRoundToHighestDigit(Int.MAX_VALUE, 2000000000)
|
||||
testRoundToHighestDigit(Int.MIN_VALUE + 1, -2000000000)
|
||||
testRoundToHighestDigit(Int.MIN_VALUE, -2000000000)
|
||||
}
|
||||
|
||||
private fun testRoundToHighestDigit(value: Int, expected: Int) {
|
||||
assertEquals(expected, roundToHighestDigit(value), "Incorrect key for value `$value`")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test round to highest digit long`() {
|
||||
// Test from -10..10
|
||||
for (i in -10L..-5L) {
|
||||
testRoundToHighestDigit(i, -10L)
|
||||
}
|
||||
for (i in -4L..-1L) {
|
||||
testRoundToHighestDigit(i, -1L)
|
||||
}
|
||||
testRoundToHighestDigit(0L, 0L)
|
||||
for (i in 1L..4L) {
|
||||
testRoundToHighestDigit(i, 1L)
|
||||
}
|
||||
for (i in 5L..10L) {
|
||||
testRoundToHighestDigit(i, 10L)
|
||||
}
|
||||
|
||||
testRoundToHighestDigit(11L, 10L)
|
||||
testRoundToHighestDigit(16L, 20L)
|
||||
testRoundToHighestDigit(64L, 60L)
|
||||
testRoundToHighestDigit(65L, 70L)
|
||||
|
||||
testRoundToHighestDigit(94L, 90L)
|
||||
testRoundToHighestDigit(95L, 100L)
|
||||
testRoundToHighestDigit(99L, 100L)
|
||||
|
||||
for (i in 1L..9L) {
|
||||
val expected = i * 1000L
|
||||
testRoundToHighestDigit(expected, expected)
|
||||
}
|
||||
|
||||
testRoundToHighestDigit(1024L, 1000L)
|
||||
testRoundToHighestDigit(1500L, 2000L)
|
||||
testRoundToHighestDigit(1999L, 2000L)
|
||||
|
||||
testRoundToHighestDigit(Long.MAX_VALUE, 9000000000000000000L)
|
||||
testRoundToHighestDigit(Long.MIN_VALUE + 1L, -9000000000000000000L)
|
||||
testRoundToHighestDigit(Long.MIN_VALUE, -9000000000000000000L)
|
||||
}
|
||||
|
||||
private fun testRoundToHighestDigit(value: Long, expected: Long) {
|
||||
assertEquals(expected, roundToHighestDigit(value), "Incorrect key for value `$value`")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test round to upper bound`() {
|
||||
// Test empty bounds return next power of two
|
||||
@@ -150,7 +239,7 @@ class StatisticsUtilTest : LightPlatformTestCase() {
|
||||
private fun testRoundToUpperBound(value: Int, bounds: IntArray, expected: Int) {
|
||||
assertEquals(expected, roundToUpperBound(value, bounds), "Incorrect key for value `$value`")
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun `test hash sensitive data`() {
|
||||
|
||||
@@ -5,6 +5,8 @@ import java.text.SimpleDateFormat
|
||||
import java.time.ZoneOffset
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
object StatisticsUtil {
|
||||
private const val kilo = 1000
|
||||
@@ -71,6 +73,62 @@ object StatisticsUtil {
|
||||
return java.lang.Long.signum(value) * nextPowerOfTwo
|
||||
}
|
||||
|
||||
/**
|
||||
* Please, use only in specific cases where precision of `roundToPowerOfTwo` is not enough
|
||||
*
|
||||
* Anonymizes sensitive project properties by rounding it to the power of ten multiplied with either:
|
||||
* - leading digit if second digit is smaller than 4 or equal to 4
|
||||
* - leading digit plus one if second digit is greater than 5 or equal to 5
|
||||
*
|
||||
* Special cases:
|
||||
* - returns the same value if all trailing digits equal zero;
|
||||
* - returns `-roundToHighestDigit(abs(value))` if the value is negative;
|
||||
* - returns 0 in case of 0;
|
||||
* - returns +/-1 for abs(value) in 1..4
|
||||
* - returns +/-10 for abs(value) in 5..10
|
||||
* - returns `roundToHighestDigit(Int.MAX_VALUE)` for Int.MIN_VALUE
|
||||
*/
|
||||
@JvmStatic
|
||||
fun roundToHighestDigit(value: Int): Int {
|
||||
if (value == 0) return 0
|
||||
val abs = if (value != Int.MIN_VALUE) abs(value) else Int.MAX_VALUE // See abs(Int) documentation
|
||||
if (abs <= 4) return Integer.signum(value) * 1
|
||||
else if (abs <= 10) return Integer.signum(value) * 10
|
||||
|
||||
var firstDigit = abs.toFloat()
|
||||
var tenPowX = 1
|
||||
while (firstDigit > 10) {
|
||||
firstDigit /= 10
|
||||
tenPowX *= 10
|
||||
}
|
||||
|
||||
// can't get overflow because second digit in max int (2147483647) is '1'
|
||||
return Integer.signum(value) * (firstDigit.roundToInt() * tenPowX)
|
||||
}
|
||||
|
||||
/**
|
||||
* Please, use only in specific cases where precision of `roundToPowerOfTwo` is not enough
|
||||
*
|
||||
* @see com.intellij.internal.statistic.utils.StatisticsUtil.roundToHighestDigit(int)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun roundToHighestDigit(value: Long): Long {
|
||||
if (value == 0L) return 0L
|
||||
val abs = if (value != Long.MIN_VALUE) abs(value) else Long.MAX_VALUE // See abs(Long) documentation
|
||||
if (abs <= 4L) return java.lang.Long.signum(value) * 1L
|
||||
else if (abs <= 10L) return java.lang.Long.signum(value) * 10L
|
||||
|
||||
var firstDigit = abs.toDouble()
|
||||
var tenPowX = 1L
|
||||
while (firstDigit > 10L) {
|
||||
firstDigit /= 10L
|
||||
tenPowX *= 10L
|
||||
}
|
||||
|
||||
// can't get overflow because second digit in max long (9223372036854775807L) is '2'
|
||||
return java.lang.Long.signum(value) * (firstDigit.roundToLong() * tenPowX)
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymizes value by finding upper bound in provided bounds.
|
||||
* Allows more fine tuning then `com.intellij.internal.statistic.utils.StatisticsUtil#roundToPowerOfTwo`
|
||||
|
||||
Reference in New Issue
Block a user