diff --git a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Fraction.scala b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Fraction.scala index 4170b21d..ebfd7c97 100644 --- a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Fraction.scala +++ b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Fraction.scala @@ -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") diff --git a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Rules.scala b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Rules.scala index fbee2414..f5ee15c0 100644 --- a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Rules.scala +++ b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Rules.scala @@ -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) } ) @@ -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) } ) @@ -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)) } ) @@ -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( @@ -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)) } ) } diff --git a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/package.scala b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/package.scala index 244c5254..ba19b872 100644 --- a/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/package.scala +++ b/duckling-fork-chinese/core/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/package.scala @@ -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)) } diff --git a/duckling-fork-chinese/learning/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Examples.scala b/duckling-fork-chinese/learning/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Examples.scala index ee27616a..a1f1cb2f 100644 --- a/duckling-fork-chinese/learning/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Examples.scala +++ b/duckling-fork-chinese/learning/src/main/scala/com/xiaomi/duckling/dimension/numeral/fraction/Examples.scala @@ -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