Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions kotlinx.fuzz.api/src/main/kotlin/kotlinx/fuzz/KFuzzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -246,20 +246,20 @@ interface KFuzzer {
* insufficiently long. In this case it will be shorter.
*
* @param maxLength the maximum length of the array
* @param range denotes desired range for each value. Should be a subset of [Float.MIN_VALUE, Float.MAX_VALUE].
* [Float.MIN_VALUE, Float.MAX_VALUE] by default.
* @param range denotes desired range for each value. Should be a subset of [-Float.MAX_VALUE, Float.MAX_VALUE].
* [-Float.MAX_VALUE, Float.MAX_VALUE] by default.
* @return nullable float array that has each value in given range
*/
fun floatsOrNull(maxLength: Int, range: FloatRange = Float.MIN_VALUE..Float.MAX_VALUE): FloatArray?
fun floatsOrNull(maxLength: Int, range: FloatRange = -Float.MAX_VALUE..Float.MAX_VALUE): FloatArray?

/**
* Consumes a not null double from the fuzzer input.
*
* @param range denotes desired range for resulting value. Should be a subset of [Double.MIN_VALUE, Double.MAX_VALUE].
* [Double.MIN_VALUE, Double.MAX_VALUE] by default.
* @param range denotes desired range for resulting value. Should be a subset of [-Double.MAX_VALUE, Double.MAX_VALUE].
* [-Double.MAX_VALUE, Double.MAX_VALUE] by default.
* @return double that has value in the given range
*/
fun double(range: DoubleRange = Double.MIN_VALUE..Double.MAX_VALUE): Double
fun double(range: DoubleRange = -Double.MAX_VALUE..Double.MAX_VALUE): Double

/**
* Consumes a nullable double from the fuzzer input.
Expand Down
75 changes: 45 additions & 30 deletions kotlinx.fuzz.engine/src/main/kotlin/kotlinx/fuzz/KFuzzerImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,49 @@ class KFuzzerImpl(data: ByteArray) : KFuzzer, Random() {
}
}

private fun fitIntoRange(
value: BigDecimal,
oldMin: BigDecimal,
oldMax: BigDecimal,
newMin: BigDecimal,
newMax: BigDecimal,
): BigDecimal {
val normalized = value.subtract(oldMin, MathContext.DECIMAL128)
.divide(oldMax.subtract(oldMin, MathContext.DECIMAL128), MathContext.DECIMAL128)

return newMin.add(
normalized.multiply(newMax.subtract(newMin, MathContext.DECIMAL128), MathContext.DECIMAL128),
MathContext.DECIMAL128,
)
private inline fun<reified T : Comparable<T>> fitIntoRange(
value: T,
newRange: ClosedFloatingPointRange<T>,
context: MathContext = MathContext.DECIMAL128,
): T {
when (value) {
is Float -> if (value.isInfinite() || value.isNaN()) {
return value
}
is Double -> if (value.isInfinite() || value.isNaN()) {
return value
}
}

val bigDecimalValue = when (value) {
is Float -> value.toBigDecimal()
is Double -> value.toBigDecimal()
else -> error("Not float type")
}

val oldUpperBound = when (T::class) {
Float::class -> Float.MAX_VALUE.toBigDecimal()
else -> Double.MAX_VALUE.toBigDecimal()
}

val normalized = bigDecimalValue.add(oldUpperBound, context).divide(oldUpperBound.multiply(BigDecimal(2), context), context)

val newLowerBound = when (T::class) {
Float::class -> (newRange.start as Float).toBigDecimal()
else -> (newRange.start as Double).toBigDecimal()
}

val newUpperBound = when (T::class) {
Float::class -> (newRange.endInclusive as Float).toBigDecimal()
else -> (newRange.endInclusive as Double).toBigDecimal()
}

val result = newLowerBound.add(normalized.multiply(newUpperBound.subtract(newLowerBound, context), context), context)

return when (T::class) {
Float::class -> result.toFloat() as T
else -> result.toDouble() as T
}
}

/**
Expand Down Expand Up @@ -258,14 +287,7 @@ class KFuzzerImpl(data: ByteArray) : KFuzzer, Random() {

override fun float(range: FloatRange): Float {
require(range.isNotEmpty()) { "range is empty" }

return fitIntoRange(
iterator.readFloat().toBigDecimal(),
Float.MIN_VALUE.toBigDecimal(),
Float.MAX_VALUE.toBigDecimal(),
range.start.toBigDecimal(),
range.endInclusive.toBigDecimal(),
).toFloat()
return fitIntoRange(iterator.readFloat(), range)
}

override fun floatOrNull(range: FloatRange): Float? {
Expand Down Expand Up @@ -298,14 +320,7 @@ class KFuzzerImpl(data: ByteArray) : KFuzzer, Random() {

override fun double(range: DoubleRange): Double {
require(range.isNotEmpty()) { "range is empty" }

return fitIntoRange(
iterator.readDouble().toBigDecimal(),
Double.MIN_VALUE.toBigDecimal(),
Double.MAX_VALUE.toBigDecimal(),
range.start.toBigDecimal(),
range.endInclusive.toBigDecimal(),
).toDouble()
return fitIntoRange(iterator.readDouble(), range)
}

override fun doubleOrNull(range: DoubleRange): Double? {
Expand Down
Loading