Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DUCK] 解决浮点数精度问题 #204

Merged
merged 1 commit into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ case object Fraction extends Dimension with Rules {
override val dimDependents: List[Dimension] = List(Numeral)
}

case class FractionData(n: Double, numerator: Double, denominator: Double) extends NumeralValue with Resolvable {
case class FractionData(n: Double, numerator: Double, denominator: Double, numeratorPrecision: Int, denominatorPrecision: Int, precision: Option[Int] = None) extends NumeralValue with Resolvable {

override def resolve(context: Types.Context,
options: Types.Options): Option[(FractionData, Boolean)] =
(FractionData(n, numerator: Double, denominator: Double), false)
(FractionData(n, numerator, denominator, numeratorPrecision, denominatorPrecision, precision), false)

override def schema: Option[String] =
if (numerator * denominator >= 0) Some(s"$numerator/$denominator")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ trait Rules extends DimRules {
pattern = List(isDimension(Numeral).predicate, "分之".regex, isPositive.predicate),
prod = tokens {
case Token(_, n1: NumeralData) :: _ :: Token(_, n2: NumeralData) :: _ =>
val v = if (n1.value == 0) 0 else n2.value / n1.value
fraction(v, n2.value, n1.value)
val v = if (n1.value == 0) 0 else (BigDecimal.apply(n2.value)./(BigDecimal.apply(n1.value))).toDouble
fraction(v, n2.value, n1.value, n2.precision, n1.precision)
}
)

Expand All @@ -39,8 +39,8 @@ trait Rules extends DimRules {
pattern = List(isDimension(Numeral).predicate, "/".regex, isDimension(Numeral).predicate),
prod = tokens {
case Token(_, n1: NumeralData) :: _ :: Token(_, n2: NumeralData) :: _ =>
val v = if (n2.value == 0) 0 else n1.value / n2.value
fraction(v, n1.value, n2.value)
val v = if (n2.value == 0) 0 else (BigDecimal.apply(n1.value)./(BigDecimal.apply(n2.value))).toDouble
fraction(v, n1.value, n2.value, n1.precision, n2.precision)
}
)

Expand All @@ -50,12 +50,12 @@ trait Rules extends DimRules {
prod = tokens {
case Token(_, GroupMatch(_ :: s1 :: s2 :: _)) :: Token(_, n: NumeralData) :: _ =>
val neg = s1.nonEmpty
val scalar = s2 match {
case "百" => if (neg) -100.0 else 100.0
case "千" => if (neg) -1000.0 else 1000.0
case "万" => if (neg) -10000.0 else 10000.0
val (scalar, precision) = s2 match {
case "百" => if (neg) (-100.0, 2) else (100.0, 2)
case "千" => if (neg) (-1000.0, 3) else (1000.0, 3)
case "万" => if (neg) (-10000.0, 4) else (10000.0, 4)
}
fraction(n.value / scalar, n.value, scalar)
fraction((BigDecimal.apply(n.value)./(BigDecimal.apply(scalar))).toDouble, n.value, scalar, n.precision, 0, Some(n.precision + precision))
}
)

Expand All @@ -64,17 +64,17 @@ trait Rules extends DimRules {
pattern = List(isDimension(Numeral).predicate, "(%|‰)".regex),
prod = tokens {
case Token(_, n: NumeralData) :: Token(_, GroupMatch(s :: _)) :: _ =>
val scalar = s match {
case "%" => 0.01
case "‰" => 0.001
val (scalar, precision) = s match {
case "%" => (0.01, 2)
case "‰" => (0.001, 3)
}
fraction(n.value * scalar, n.value, 1/scalar)
fraction((BigDecimal.apply(n.value).*(BigDecimal.apply(scalar))).toDouble, n.value, 1/scalar, n.precision, 0, Some(n.precision + precision))
}
)

val oneHalf =
Rule(name = "<1> half", pattern = List(isIntegerBetween(1, 1).predicate, "半".regex), prod = tokens {
case _ => fraction(0.5, 50.0, 100.0)
case _ => fraction(0.5, 50.0, 100.0, 0, 0, Some(2))
})

val hundredPercentRule = Rule(
Expand All @@ -84,7 +84,7 @@ trait Rules extends DimRules {
case Token(RegexMatch, GroupMatch(_ :: m :: _)) :: _ =>
val scalar = if (m.nonEmpty) -100.0 else 100.0
val value = 100.0 / scalar
fraction(value, 100.0, scalar)
fraction(value, 100.0, scalar, 0, 0, Some(2))
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ package com.xiaomi.duckling.dimension.numeral
import com.xiaomi.duckling.Types.Token

package object fraction {
def fraction(v: Double, numerator: Double, denominator: Double): Token = Token(Fraction, FractionData(v, numerator, denominator))
def fraction(v: Double, numerator: Double, denominator: Double, numeratorPrecision: Int, denominatorPrecision: Int, precision: Option[Int] = None): Token = Token(Fraction, FractionData(v, numerator, denominator, numeratorPrecision, denominatorPrecision, precision))
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@ object Examples extends DimExamples {

override def pairs: List[(Types.ResolvedValue, List[String])] =
List(
(0.6, 60.0, 100.0, List("百分之六十")),
(0.6, 600.0, 1000.0, List("千分之六百")),
(0.75, 3.0, 4.0, List("4分之3", "四分之3", "3/4")),
(0.5, 64.0, 128.0, List("一百二十八分之64")),
(0.5, 50.0, 100.0, List("一半", "50%", "五十%")),
(0.5, 60.0, 120.0, List("六十/一百二十")),
(-0.6, 60.0, -100.0, List("负百分之六十", "负的百分之六十")),
(-1.0, 100.0, -100.0, List("负百分之百", "负的百分之百", "负的百分之一百")),
(1.0, 100.0, 100.0, List("百分之一百", "百分百", "百分之百"))
(0.6, 60.0, 100.0, 0, 0, Some(2), List("百分之六十")),
(0.7, 70.0, 100.0, 0, 0, Some(2), List("70%")),
(0.6, 600.0, 1000.0, 0, 0, Some(3), List("千分之六百")),
(0.75, 3.0, 4.0, 0, 0, None, List("4分之3", "四分之3", "3/4")),
(0.5, 64.0, 128.0, 0, 0, None, List("一百二十八分之64")),
(0.5, 50.0, 100.0, 0, 0, Some(2), List("一半", "50%", "五十%")),
(0.5, 60.0, 120.0, 0, 0, None, List("六十/一百二十")),
(-0.6, 60.0, -100.0, 0, 0, Some(2), List("负百分之六十", "负的百分之六十")),
(-1.0, 100.0, -100.0, 0, 0, Some(2), List("负百分之百", "负的百分之百", "负的百分之一百")),
(1.0, 100.0, 100.0, 0, 0, Some(2), List("百分之一百", "百分百", "百分之百")),
(0.5, 1.5, 3.0, 1, 0, None, List("三分之一点五", "1.5/3")),
(0.1562, 15.62, 100.0, 2, 0, Some(4), List("百分之十五点六二", "15.62%")),
(0.2, 2.5, 12.5, 1, 1, None, List("十二点五分之二点五", "2.5/12.5"))
).map {
case (expected, numerator, denominator, texts) => (FractionData(expected, numerator, denominator), texts)
case (expected, numerator, denominator, numeratorPrecision, denominatorPrecision, precision, texts) => (FractionData(expected, numerator, denominator, numeratorPrecision, denominatorPrecision, precision), texts)
}

override val dimension: Dimension = Fraction
Expand Down
Loading