ICU-20708 Fixing edge cases with negative infinity and NaN.

diff --git a/icu4c/source/i18n/fmtable.cpp b/icu4c/source/i18n/fmtable.cpp
index d813424..dbfd3c2 100644
--- a/icu4c/source/i18n/fmtable.cpp
+++ b/icu4c/source/i18n/fmtable.cpp
@@ -736,7 +736,7 @@
         fDecimalStr->append("Infinity", status);
       } else if (fDecimalQuantity->isNaN()) {
         fDecimalStr->append("NaN", status);
-      } else if (fDecimalQuantity->isZero()) {
+      } else if (fDecimalQuantity->isZeroish()) {
         fDecimalStr->append("0", -1, status);
       } else if (fType==kLong || fType==kInt64 || // use toPlainString for integer types
                   (fDecimalQuantity->getMagnitude() != INT32_MIN && std::abs(fDecimalQuantity->getMagnitude()) < 5)) {
diff --git a/icu4c/source/i18n/number_compact.cpp b/icu4c/source/i18n/number_compact.cpp
index f330251..3d25999 100644
--- a/icu4c/source/i18n/number_compact.cpp
+++ b/icu4c/source/i18n/number_compact.cpp
@@ -272,15 +272,15 @@
     parent->processQuantity(quantity, micros, status);
     if (U_FAILURE(status)) { return; }
 
-    // Treat zero as if it had magnitude 0
+    // Treat zero, NaN, and infinity as if they had magnitude 0
     int32_t magnitude;
-    if (quantity.isZero()) {
+    if (quantity.isZeroish()) {
         magnitude = 0;
         micros.rounder.apply(quantity, status);
     } else {
         // TODO: Revisit chooseMultiplierAndApply
         int32_t multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
-        magnitude = quantity.isZero() ? 0 : quantity.getMagnitude();
+        magnitude = quantity.isZeroish() ? 0 : quantity.getMagnitude();
         magnitude -= multiplier;
     }
 
diff --git a/icu4c/source/i18n/number_decimalquantity.cpp b/icu4c/source/i18n/number_decimalquantity.cpp
index d899c27..2c4c2ce 100644
--- a/icu4c/source/i18n/number_decimalquantity.cpp
+++ b/icu4c/source/i18n/number_decimalquantity.cpp
@@ -205,7 +205,7 @@
 }
 
 void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
-    if (isInfinite() || isZero() || isNaN()) {
+    if (isZeroish()) {
         return;
     }
     // Convert to DecNum, multiply, and convert back.
@@ -218,7 +218,7 @@
 }
 
 void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) {
-    if (isInfinite() || isZero() || isNaN()) {
+    if (isZeroish()) {
         return;
     }
     // Convert to DecNum, multiply, and convert back.
@@ -318,8 +318,14 @@
     return (flags & NEGATIVE_FLAG) != 0;
 }
 
-int8_t DecimalQuantity::signum() const {
-    return isNegative() ? -1 : isZero() ? 0 : 1;
+Signum DecimalQuantity::signum() const {
+    if (isNegative()) {
+        return SIGNUM_NEG;
+    } else if (isZeroish() && !isInfinite()) {
+        return SIGNUM_ZERO;
+    } else {
+        return SIGNUM_POS;
+    }
 }
 
 bool DecimalQuantity::isInfinite() const {
@@ -330,7 +336,7 @@
     return (flags & NAN_FLAG) != 0;
 }
 
-bool DecimalQuantity::isZero() const {
+bool DecimalQuantity::isZeroish() const {
     return precision == 0;
 }
 
@@ -548,7 +554,10 @@
 }
 
 bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
-    if (isZero()) {
+    if (isInfinite() || isNaN()) {
+        return false;
+    }
+    if (isZeroish()) {
         return true;
     }
     if (scale < 0 && !ignoreFraction) {
diff --git a/icu4c/source/i18n/number_decimalquantity.h b/icu4c/source/i18n/number_decimalquantity.h
index 06cc836..4ec6c5a 100644
--- a/icu4c/source/i18n/number_decimalquantity.h
+++ b/icu4c/source/i18n/number_decimalquantity.h
@@ -146,14 +146,17 @@
      */
     int32_t getMagnitude() const;
 
-    /** @return Whether the value represented by this {@link DecimalQuantity} is zero. */
-    bool isZero() const;
+    /**
+     * @return Whether the value represented by this {@link DecimalQuantity} is
+     * zero, infinity, or NaN.
+     */
+    bool isZeroish() const;
 
     /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
     bool isNegative() const;
 
-    /** @return -1 if the value is negative; 1 if positive; or 0 if zero. */
-    int8_t signum() const;
+    /** @return The appropriate value from the Signum enum. */
+    Signum signum() const;
 
     /** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
     bool isInfinite() const U_OVERRIDE;
diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp
index bd49a12..2dbd2fa 100644
--- a/icu4c/source/i18n/number_fluent.cpp
+++ b/icu4c/source/i18n/number_fluent.cpp
@@ -697,7 +697,7 @@
 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
                                             UErrorCode& status) const {
     FormattedStringBuilder string;
-    auto signum = static_cast<int8_t>(isNegative ? -1 : 1);
+    auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS);
     // Always return affixes for plural form OTHER.
     static const StandardPlural::Form plural = StandardPlural::OTHER;
     int32_t prefixLength;
diff --git a/icu4c/source/i18n/number_formatimpl.cpp b/icu4c/source/i18n/number_formatimpl.cpp
index 8741af3..fde97fb 100644
--- a/icu4c/source/i18n/number_formatimpl.cpp
+++ b/icu4c/source/i18n/number_formatimpl.cpp
@@ -81,7 +81,7 @@
     return length;
 }
 
-int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
+int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, Signum signum,
                                                    StandardPlural::Form plural,
                                                    FormattedStringBuilder& outString, UErrorCode& status) {
     NumberFormatterImpl impl(macros, false, status);
@@ -129,7 +129,7 @@
     return fMicros;
 }
 
-int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural,
+int32_t NumberFormatterImpl::getPrefixSuffix(Signum signum, StandardPlural::Form plural,
                                              FormattedStringBuilder& outString, UErrorCode& status) const {
     if (U_FAILURE(status)) { return 0; }
     // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier).
@@ -140,7 +140,7 @@
     return modifier->getPrefixLength();
 }
 
-int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
+int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
                                                    FormattedStringBuilder& outString, UErrorCode& status) {
     if (U_FAILURE(status)) { return 0; }
     // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier).
diff --git a/icu4c/source/i18n/number_formatimpl.h b/icu4c/source/i18n/number_formatimpl.h
index 44753c0..206c5f5 100644
--- a/icu4c/source/i18n/number_formatimpl.h
+++ b/icu4c/source/i18n/number_formatimpl.h
@@ -44,7 +44,7 @@
      * @return The index into the output at which the prefix ends and the suffix starts; in other words,
      *         the prefix length.
      */
-    static int32_t getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
+    static int32_t getPrefixSuffixStatic(const MacroProps& macros, Signum signum,
                                          StandardPlural::Form plural, FormattedStringBuilder& outString,
                                          UErrorCode& status);
 
@@ -61,7 +61,7 @@
     /**
      * Like getPrefixSuffixStatic() but uses the safe compiled object.
      */
-    int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, FormattedStringBuilder& outString,
+    int32_t getPrefixSuffix(Signum signum, StandardPlural::Form plural, FormattedStringBuilder& outString,
                             UErrorCode& status) const;
 
     const MicroProps& getRawMicroProps() const {
@@ -109,7 +109,7 @@
 
     MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
 
-    int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
+    int32_t getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
                                   FormattedStringBuilder& outString, UErrorCode& status);
 
     /**
diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp
index 0cd1600..bd41699 100644
--- a/icu4c/source/i18n/number_longnames.cpp
+++ b/icu4c/source/i18n/number_longnames.cpp
@@ -289,7 +289,7 @@
         if (U_FAILURE(status)) { return; }
         SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
         if (U_FAILURE(status)) { return; }
-        fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, 0, plural});
+        fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, SIGNUM_ZERO, plural});
     }
 }
 
@@ -306,7 +306,7 @@
         if (U_FAILURE(status)) { return; }
         SimpleFormatter compoundCompiled(compoundFormat, 0, 1, status);
         if (U_FAILURE(status)) { return; }
-        fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, 0, plural});
+        fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, SIGNUM_ZERO, plural});
     }
 }
 
@@ -317,7 +317,7 @@
     micros.modOuter = &fModifiers[pluralForm];
 }
 
-const Modifier* LongNameHandler::getModifier(int8_t /*signum*/, StandardPlural::Form plural) const {
+const Modifier* LongNameHandler::getModifier(Signum /*signum*/, StandardPlural::Form plural) const {
     return &fModifiers[plural];
 }
 
diff --git a/icu4c/source/i18n/number_longnames.h b/icu4c/source/i18n/number_longnames.h
index 76fb82d..38aca26 100644
--- a/icu4c/source/i18n/number_longnames.h
+++ b/icu4c/source/i18n/number_longnames.h
@@ -34,7 +34,7 @@
     void
     processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
 
-    const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE;
+    const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
 
   private:
     SimpleModifier fModifiers[StandardPlural::Form::COUNT];
diff --git a/icu4c/source/i18n/number_modifiers.cpp b/icu4c/source/i18n/number_modifiers.cpp
index aa6cf57..3a44f8f 100644
--- a/icu4c/source/i18n/number_modifiers.cpp
+++ b/icu4c/source/i18n/number_modifiers.cpp
@@ -57,7 +57,7 @@
         : obj(nullptr) {}
 
 Modifier::Parameters::Parameters(
-    const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural)
+    const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural)
         : obj(_obj), signum(_signum), plural(_plural) {}
 
 ModifierStore::~ModifierStore() = default;
diff --git a/icu4c/source/i18n/number_modifiers.h b/icu4c/source/i18n/number_modifiers.h
index 5c13c87..c84c6aa 100644
--- a/icu4c/source/i18n/number_modifiers.h
+++ b/icu4c/source/i18n/number_modifiers.h
@@ -289,7 +289,7 @@
     /**
      * Sets the Modifier with the specified signum and plural form.
      */
-    void adoptModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
+    void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
         U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
         mods[getModIndex(signum, plural)] = mod;
     }
@@ -298,13 +298,13 @@
      * Sets the Modifier with the specified signum.
      * The modifier will apply to all plural forms.
      */
-    void adoptModifierWithoutPlural(int8_t signum, const Modifier *mod) {
+    void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
         U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
         mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
     }
 
     /** Returns a reference to the modifier; no ownership change. */
-    const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE {
+    const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE {
         const Modifier* modifier = mods[getModIndex(signum, plural)];
         if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
             modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
@@ -313,7 +313,7 @@
     }
 
     /** Returns a reference to the modifier; no ownership change. */
-    const Modifier *getModifierWithoutPlural(int8_t signum) const {
+    const Modifier *getModifierWithoutPlural(Signum signum) const {
         return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
     }
 
@@ -321,7 +321,7 @@
     // NOTE: mods is zero-initialized (to nullptr)
     const Modifier *mods[3 * StandardPlural::COUNT] = {};
 
-    inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) {
+    inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
         U_ASSERT(signum >= -1 && signum <= 1);
         U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
         return static_cast<int32_t>(plural) * 3 + (signum + 1);
diff --git a/icu4c/source/i18n/number_patternmodifier.cpp b/icu4c/source/i18n/number_patternmodifier.cpp
index 8f3af2a..724f5b9 100644
--- a/icu4c/source/i18n/number_patternmodifier.cpp
+++ b/icu4c/source/i18n/number_patternmodifier.cpp
@@ -43,7 +43,7 @@
     fRules = rules;
 }
 
-void MutablePatternModifier::setNumberProperties(int8_t signum, StandardPlural::Form plural) {
+void MutablePatternModifier::setNumberProperties(Signum signum, StandardPlural::Form plural) {
     fSignum = signum;
     fPlural = plural;
 }
@@ -79,12 +79,12 @@
     if (needsPlurals()) {
         // Slower path when we require the plural keyword.
         for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
-            setNumberProperties(1, plural);
-            pm->adoptModifier(1, plural, createConstantModifier(status));
-            setNumberProperties(0, plural);
-            pm->adoptModifier(0, plural, createConstantModifier(status));
-            setNumberProperties(-1, plural);
-            pm->adoptModifier(-1, plural, createConstantModifier(status));
+            setNumberProperties(SIGNUM_POS, plural);
+            pm->adoptModifier(SIGNUM_POS, plural, createConstantModifier(status));
+            setNumberProperties(SIGNUM_ZERO, plural);
+            pm->adoptModifier(SIGNUM_ZERO, plural, createConstantModifier(status));
+            setNumberProperties(SIGNUM_NEG, plural);
+            pm->adoptModifier(SIGNUM_NEG, plural, createConstantModifier(status));
         }
         if (U_FAILURE(status)) {
             delete pm;
@@ -93,12 +93,12 @@
         return new ImmutablePatternModifier(pm, fRules, parent);  // adopts pm
     } else {
         // Faster path when plural keyword is not needed.
-        setNumberProperties(1, StandardPlural::Form::COUNT);
-        pm->adoptModifierWithoutPlural(1, createConstantModifier(status));
-        setNumberProperties(0, StandardPlural::Form::COUNT);
-        pm->adoptModifierWithoutPlural(0, createConstantModifier(status));
-        setNumberProperties(-1, StandardPlural::Form::COUNT);
-        pm->adoptModifierWithoutPlural(-1, createConstantModifier(status));
+        setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
+        pm->adoptModifierWithoutPlural(SIGNUM_POS, createConstantModifier(status));
+        setNumberProperties(SIGNUM_ZERO, StandardPlural::Form::COUNT);
+        pm->adoptModifierWithoutPlural(SIGNUM_ZERO, createConstantModifier(status));
+        setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
+        pm->adoptModifierWithoutPlural(SIGNUM_NEG, createConstantModifier(status));
         if (U_FAILURE(status)) {
             delete pm;
             return nullptr;
@@ -140,7 +140,7 @@
     }
 }
 
-const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const {
+const Modifier* ImmutablePatternModifier::getModifier(Signum signum, StandardPlural::Form plural) const {
     if (rules == nullptr) {
         return pm->getModifierWithoutPlural(signum);
     } else {
diff --git a/icu4c/source/i18n/number_patternmodifier.h b/icu4c/source/i18n/number_patternmodifier.h
index 59ea02f..b2c90e0 100644
--- a/icu4c/source/i18n/number_patternmodifier.h
+++ b/icu4c/source/i18n/number_patternmodifier.h
@@ -48,7 +48,7 @@
 
     void applyToMicros(MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const;
 
-    const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const;
+    const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const;
 
   private:
     ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
@@ -142,7 +142,7 @@
      *            The plural form of the number, required only if the pattern contains the triple
      *            currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
      */
-    void setNumberProperties(int8_t signum, StandardPlural::Form plural);
+    void setNumberProperties(Signum signum, StandardPlural::Form plural);
 
     /**
      * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
@@ -223,7 +223,7 @@
     const PluralRules *fRules;
 
     // Number details (initialized in setNumberProperties)
-    int8_t fSignum;
+    Signum fSignum;
     StandardPlural::Form fPlural;
 
     // QuantityChain details (initialized in addToChain)
diff --git a/icu4c/source/i18n/number_patternstring.cpp b/icu4c/source/i18n/number_patternstring.cpp
index 9075424..c7212c1 100644
--- a/icu4c/source/i18n/number_patternstring.cpp
+++ b/icu4c/source/i18n/number_patternstring.cpp
@@ -352,7 +352,7 @@
                 result.groupingSizes += 1;
                 result.integerNumerals += 1;
                 result.integerTotal += 1;
-                if (!result.rounding.isZero() || state.peek() != u'0') {
+                if (!result.rounding.isZeroish() || state.peek() != u'0') {
                     result.rounding.appendDigit(static_cast<int8_t>(state.peek() - u'0'), 0, true);
                 }
                 break;
@@ -532,7 +532,7 @@
         properties.roundingIncrement = 0.0;
         properties.minimumSignificantDigits = positive.integerAtSigns;
         properties.maximumSignificantDigits = positive.integerAtSigns + positive.integerTrailingHashSigns;
-    } else if (!positive.rounding.isZero()) {
+    } else if (!positive.rounding.isZeroish()) {
         if (!ignoreRounding) {
             properties.minimumFractionDigits = minFrac;
             properties.maximumFractionDigits = positive.fractionTotal;
@@ -1000,7 +1000,7 @@
 }
 
 void PatternStringUtils::patternInfoToStringBuilder(const AffixPatternProvider& patternInfo, bool isPrefix,
-                                                    int8_t signum, UNumberSignDisplay signDisplay,
+                                                    Signum signum, UNumberSignDisplay signDisplay,
                                                     StandardPlural::Form plural,
                                                     bool perMilleReplacesPercent, UnicodeString& output) {
 
@@ -1014,6 +1014,7 @@
 
     // Should we use the affix from the negative subpattern? (If not, we will use the positive
     // subpattern.)
+    // TODO: Deal with signum
     bool useNegativeAffixPattern = patternInfo.hasNegativeSubpattern() && (
             signum == -1 || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign));
 
diff --git a/icu4c/source/i18n/number_patternstring.h b/icu4c/source/i18n/number_patternstring.h
index 0c90867..1191d29 100644
--- a/icu4c/source/i18n/number_patternstring.h
+++ b/icu4c/source/i18n/number_patternstring.h
@@ -295,7 +295,7 @@
      * substitution, and plural forms for CurrencyPluralInfo.
      */
     static void patternInfoToStringBuilder(const AffixPatternProvider& patternInfo, bool isPrefix,
-                                           int8_t signum, UNumberSignDisplay signDisplay,
+                                           Signum signum, UNumberSignDisplay signDisplay,
                                            StandardPlural::Form plural, bool perMilleReplacesPercent,
                                            UnicodeString& output);
 
diff --git a/icu4c/source/i18n/number_rounding.cpp b/icu4c/source/i18n/number_rounding.cpp
index 9e369f7..813d4b6 100644
--- a/icu4c/source/i18n/number_rounding.cpp
+++ b/icu4c/source/i18n/number_rounding.cpp
@@ -33,7 +33,7 @@
     if (maxSig == -1) {
         return INT32_MIN;
     }
-    int magnitude = value.isZero() ? 0 : value.getMagnitude();
+    int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
     return magnitude - maxSig + 1;
 }
 
@@ -45,7 +45,7 @@
 }
 
 int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig) {
-    int magnitude = value.isZero() ? 0 : value.getMagnitude();
+    int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
     return magnitude - minSig + 1;
 }
 
@@ -306,8 +306,8 @@
 int32_t
 RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer,
                                   UErrorCode &status) {
-    // Do not call this method with zero.
-    U_ASSERT(!input.isZero());
+    // Do not call this method with zero, NaN, or infinity.
+    U_ASSERT(!input.isZeroish());
 
     // Perform the first attempt at rounding.
     int magnitude = input.getMagnitude();
@@ -316,7 +316,7 @@
     apply(input, status);
 
     // If the number rounded to zero, exit.
-    if (input.isZero() || U_FAILURE(status)) {
+    if (input.isZeroish() || U_FAILURE(status)) {
         return multiplier;
     }
 
@@ -374,7 +374,7 @@
             value.setMinFraction(
                     uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)));
             // Make sure that digits are displayed on zero.
-            if (value.isZero() && fPrecision.fUnion.fracSig.fMinSig > 0) {
+            if (value.isZeroish() && fPrecision.fUnion.fracSig.fMinSig > 0) {
                 value.setMinInteger(1);
             }
             break;
@@ -436,7 +436,7 @@
 void RoundingImpl::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*status*/) {
     // This method is intended for the one specific purpose of helping print "00.000E0".
     U_ASSERT(isSignificantDigits());
-    U_ASSERT(value.isZero());
+    U_ASSERT(value.isZeroish());
     value.setMinFraction(fPrecision.fUnion.fracSig.fMinSig - minInt);
 }
 
diff --git a/icu4c/source/i18n/number_scientific.cpp b/icu4c/source/i18n/number_scientific.cpp
index 6fb4c19..f3de741 100644
--- a/icu4c/source/i18n/number_scientific.cpp
+++ b/icu4c/source/i18n/number_scientific.cpp
@@ -123,9 +123,15 @@
     fParent->processQuantity(quantity, micros, status);
     if (U_FAILURE(status)) { return; }
 
+    // Do not apply scientific notation to special doubles
+    if (quantity.isInfinite() || quantity.isNaN()) {
+        micros.modInner = &micros.helpers.emptyStrongModifier;
+        return;
+    }
+
     // Treat zero as if it had magnitude 0
     int32_t exponent;
-    if (quantity.isZero()) {
+    if (quantity.isZeroish()) {
         if (fSettings.fRequireMinInt && micros.rounder.isSignificantDigits()) {
             // Show "00.000E0" on pattern "00.000E0"
             micros.rounder.apply(quantity, fSettings.fEngineeringInterval, status);
diff --git a/icu4c/source/i18n/number_types.h b/icu4c/source/i18n/number_types.h
index 5aeead7..d62aa6a 100644
--- a/icu4c/source/i18n/number_types.h
+++ b/icu4c/source/i18n/number_types.h
@@ -91,6 +91,12 @@
     TYPE_DECIMAL, TYPE_CURRENCY
 };
 
+enum Signum {
+    SIGNUM_NEG = -1,
+    SIGNUM_ZERO = 0,
+    SIGNUM_POS = 1
+};
+
 
 class U_I18N_API AffixPatternProvider {
   public:
@@ -194,11 +200,11 @@
      */
     struct U_I18N_API Parameters {
         const ModifierStore* obj = nullptr;
-        int8_t signum;
+        Signum signum;
         StandardPlural::Form plural;
 
         Parameters();
-        Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural);
+        Parameters(const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural);
     };
 
     /**
@@ -229,7 +235,7 @@
     /**
      * Returns a Modifier with the given parameters (best-effort).
      */
-    virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0;
+    virtual const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const = 0;
 };
 
 
diff --git a/icu4c/source/i18n/numparse_affixes.cpp b/icu4c/source/i18n/numparse_affixes.cpp
index 6dc30d2..cf8bab4 100644
--- a/icu4c/source/i18n/numparse_affixes.cpp
+++ b/icu4c/source/i18n/numparse_affixes.cpp
@@ -281,7 +281,9 @@
     AffixPatternMatcher* posSuffix = nullptr;
 
     // Pre-process the affix strings to resolve LDML rules like sign display.
-    for (int8_t signum = 1; signum >= -1; signum--) {
+    for (int8_t signumInt = 1; signumInt >= -1; signumInt--) {
+        auto signum = static_cast<Signum>(signumInt);
+
         // Generate Prefix
         bool hasPrefix = false;
         PatternStringUtils::patternInfoToStringBuilder(
diff --git a/icu4c/source/i18n/numparse_parsednumber.cpp b/icu4c/source/i18n/numparse_parsednumber.cpp
index 6485d17..4b373a3 100644
--- a/icu4c/source/i18n/numparse_parsednumber.cpp
+++ b/icu4c/source/i18n/numparse_parsednumber.cpp
@@ -74,7 +74,7 @@
         status = U_INVALID_STATE_ERROR;
         return 0.0;
     }
-    if (quantity.isZero() && quantity.isNegative()) {
+    if (quantity.isZeroish() && quantity.isNegative()) {
         return -0.0;
     }
 
@@ -107,7 +107,7 @@
         }
     }
     U_ASSERT(!quantity.bogus);
-    if (quantity.isZero() && quantity.isNegative() && !integerOnly) {
+    if (quantity.isZeroish() && quantity.isNegative() && !integerOnly) {
         output.setDouble(-0.0);
         return;
     }
diff --git a/icu4c/source/i18n/unicode/unumberformatter.h b/icu4c/source/i18n/unicode/unumberformatter.h
index e4c21a4..b38763c 100644
--- a/icu4c/source/i18n/unicode/unumberformatter.h
+++ b/icu4c/source/i18n/unicode/unumberformatter.h
@@ -344,7 +344,7 @@
 
     /**
      * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a
-     * sign on zero.
+     * sign on zero or NaN, unless the sign bit is set (-0.0 gets a sign).
      *
      * @draft ICU 61
      */
@@ -352,8 +352,9 @@
 
     /**
      * Use the locale-dependent accounting format on negative numbers, and show the plus sign on
-     * positive numbers. Do not show a sign on zero. For more information on the accounting format,
-     * see the ACCOUNTING sign display strategy.
+     * positive numbers. Do not show a sign on zero or NaN, unless the sign bit is set (-0.0 gets a
+     * sign). For more information on the accounting format, see the ACCOUNTING sign display
+     * strategy.
      *
      * @draft ICU 61
      */
diff --git a/icu4c/source/test/intltest/numbertest.h b/icu4c/source/test/intltest/numbertest.h
index d139bc0..61a46e8 100644
--- a/icu4c/source/test/intltest/numbertest.h
+++ b/icu4c/source/test/intltest/numbertest.h
@@ -68,6 +68,7 @@
     // TODO: Add this method if currency symbols override support is added.
     //void symbolsOverride();
     void sign();
+    void signCoverage();
     void decimal();
     void scale();
     void locale();
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 8c448c9..cfc10ab 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -86,6 +86,7 @@
         // TODO: Add this method if currency symbols override support is added.
         //TESTCASE_AUTO(symbolsOverride);
         TESTCASE_AUTO(sign);
+        TESTCASE_AUTO(signCoverage);
         TESTCASE_AUTO(decimal);
         TESTCASE_AUTO(scale);
         TESTCASE_AUTO(locale);
@@ -216,6 +217,22 @@
             Locale::getEnglish(),
             -1000000,
             u"-1E6");
+
+    assertFormatSingle(
+            u"Scientific Infinity",
+            u"scientific",
+            NumberFormatter::with().notation(Notation::scientific()),
+            Locale::getEnglish(),
+            -uprv_getInfinity(),
+            u"-∞");
+
+    assertFormatSingle(
+            u"Scientific NaN",
+            u"scientific",
+            NumberFormatter::with().notation(Notation::scientific()),
+            Locale::getEnglish(),
+            uprv_getNaN(),
+            u"NaN");
 }
 
 void NumberFormatterApiTest::notationCompact() {
@@ -432,6 +449,22 @@
             1e7,
             u"1000\u842C");
 
+    assertFormatSingle(
+            u"Compact Infinity",
+            u"compact-short",
+            NumberFormatter::with().notation(Notation::compactShort()),
+            Locale::getEnglish(),
+            -uprv_getInfinity(),
+            u"-∞");
+
+    assertFormatSingle(
+            u"Compact NaN",
+            u"compact-short",
+            NumberFormatter::with().notation(Notation::compactShort()),
+            Locale::getEnglish(),
+            uprv_getNaN(),
+            u"NaN");
+
     // NOTE: There is no API for compact custom data in C++
     // and thus no "Compact Somali No Figure" test
 }
@@ -2069,6 +2102,39 @@
             u"-444,444.00 US dollars");
 }
 
+void NumberFormatterApiTest::signCoverage() {
+    // https://unicode-org.atlassian.net/browse/ICU-20708
+    IcuTestErrorCode status(*this, "signCoverage");
+    const struct TestCase {
+        UNumberSignDisplay sign;
+        const char16_t* expectedStrings[8];
+    } cases[] = {
+        { UNUM_SIGN_AUTO, {        u"-∞", u"-1", u"-0",  u"0",  u"1",  u"∞",  u"NaN", u"-NaN" } },
+        { UNUM_SIGN_ALWAYS, {      u"-∞", u"-1", u"-0", u"+0", u"+1", u"+∞", u"+NaN", u"-NaN" } },
+        { UNUM_SIGN_NEVER, {        u"∞",  u"1",  u"0",  u"0",  u"1",  u"∞",  u"NaN",  u"NaN" } },
+        { UNUM_SIGN_EXCEPT_ZERO, { u"-∞", u"-1", u"-0",  u"0", u"+1", u"+∞",  u"NaN", u"-NaN" } },
+    };
+    double negNaN = std::copysign(uprv_getNaN(), -0.0);
+    const double inputs[] = {
+        -uprv_getInfinity(), -1, -0.0, 0, 1, uprv_getInfinity(), uprv_getNaN(), negNaN
+    };
+    for (auto& cas : cases) {
+        auto sign = cas.sign;
+        for (int32_t i = 0; i < UPRV_LENGTHOF(inputs); i++) {
+            auto input = inputs[i];
+            auto expected = cas.expectedStrings[i];
+            auto actual = NumberFormatter::with()
+                .sign(sign)
+                .locale(Locale::getUS())
+                .formatDouble(input, status)
+                .toString(status);
+            assertEquals(
+                DoubleToUnicodeString(input) + " " + Int64ToUnicodeString(sign),
+                expected, actual);
+        }
+    }
+}
+
 void NumberFormatterApiTest::decimal() {
     assertFormatDescending(
             u"Decimal Default",
diff --git a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
index e557dcf..8f61242 100644
--- a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
+++ b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
@@ -35,19 +35,19 @@
     }
     mod.setSymbols(&symbols, &currencySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
 
-    mod.setNumberProperties(1, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
     assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
-    mod.setNumberProperties(0, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_ZERO, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
     assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
-    mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b", u"-a", getPrefix(mod, status));
     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
@@ -60,19 +60,19 @@
     assertSuccess("Spot 4", status);
     mod.setPatternInfo(&patternInfo2, UNUM_FIELD_COUNT);
     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
-    mod.setNumberProperties(1, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
     assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
     assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
-    mod.setNumberProperties(0, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_ZERO, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
     assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
     assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
-    mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b;c-0d", u"c-", getPrefix(mod, status));
     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
     mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
@@ -96,7 +96,7 @@
         return;
     }
     mod.setSymbols(&symbols, &currencySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
-    mod.setNumberProperties(1, StandardPlural::Form::COUNT);
+    mod.setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
 
     // Unsafe Code Path
     FormattedStringBuilder nsb;
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity.java
index 258274f..d551c32 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity.java
@@ -121,8 +121,11 @@
      */
     public int getMagnitude() throws ArithmeticException;
 
-    /** @return Whether the value represented by this {@link DecimalQuantity} is zero. */
-    public boolean isZero();
+    /**
+     * @return Whether the value represented by this {@link DecimalQuantity} is
+     * zero, infinity, or NaN.
+     */
+    public boolean isZeroish();
 
     /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
     public boolean isNegative();
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
index 58a04c8..badc530 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
@@ -183,7 +183,7 @@
 
     @Override
     public void multiplyBy(BigDecimal multiplicand) {
-        if (isInfinite() || isZero() || isNaN()) {
+        if (isZeroish()) {
             return;
         }
         BigDecimal temp = toBigDecimal();
@@ -304,7 +304,7 @@
 
     @Override
     public int signum() {
-        return isNegative() ? -1 : isZero() ? 0 : 1;
+        return isNegative() ? -1 : (isZeroish() && !isInfinite()) ? 0 : 1;
     }
 
     @Override
@@ -318,7 +318,7 @@
     }
 
     @Override
-    public boolean isZero() {
+    public boolean isZeroish() {
         return precision == 0;
     }
 
@@ -398,8 +398,10 @@
     public void setToDouble(double n) {
         setBcdToZero();
         flags = 0;
-        // Double.compare() handles +0.0 vs -0.0
-        if (Double.compare(n, 0.0) < 0) {
+        // The sign bit is the top bit in both double and long, so we can
+        // get the long bits for the double and compare it to zero to check
+        // the sign of the double.
+        if (Double.doubleToRawLongBits(n) < 0) {
             flags |= NEGATIVE_FLAG;
             n = -n;
         }
@@ -619,7 +621,10 @@
      * Returns whether or not a Long can fully represent the value stored in this DecimalQuantity.
      */
     public boolean fitsInLong() {
-        if (isZero()) {
+        if (isInfinite() || isNaN()) {
+            return false;
+        }
+        if (isZeroish()) {
             return true;
         }
         if (scale < 0) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java
index 315eac3..72f737f 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java
@@ -153,7 +153,7 @@
             }
         }
         assert quantity != null;
-        if (quantity.isZero() && quantity.isNegative() && !integerOnly) {
+        if (quantity.isZeroish() && quantity.isNegative() && !integerOnly) {
             return -0.0;
         }
 
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
index 9502dc3..806f341 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
@@ -122,14 +122,14 @@
             MicroProps micros = parent.processQuantity(quantity);
             assert micros.rounder != null;
 
-            // Treat zero as if it had magnitude 0
+            // Treat zero, NaN, and infinity as if they had magnitude 0
             int magnitude;
-            if (quantity.isZero()) {
+            if (quantity.isZeroish()) {
                 magnitude = 0;
                 micros.rounder.apply(quantity);
             } else {
                 int multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data);
-                magnitude = quantity.isZero() ? 0 : quantity.getMagnitude();
+                magnitude = quantity.isZeroish() ? 0 : quantity.getMagnitude();
                 magnitude -= multiplier;
             }
 
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java
index 928055d..b109e85 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java
@@ -346,7 +346,7 @@
 
         /**
          * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a
-         * sign on zero.
+         * sign on zero or NaN, unless the sign bit is set (-0.0 gets a sign).
          *
          * @draft ICU 61
          * @provisional This API might change or be removed in a future release.
@@ -356,8 +356,9 @@
 
         /**
          * Use the locale-dependent accounting format on negative numbers, and show the plus sign on
-         * positive numbers. Do not show a sign on zero. For more information on the accounting format,
-         * see the ACCOUNTING sign display strategy.
+         * positive numbers. Do not show a sign on zero or NaN, unless the sign bit is set (-0.0 gets a
+         * sign). For more information on the accounting format, see the ACCOUNTING sign display
+         * strategy.
          *
          * @draft ICU 61
          * @provisional This API might change or be removed in a future release.
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/Precision.java b/icu4j/main/classes/core/src/com/ibm/icu/number/Precision.java
index f239f9a..41795a2 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/Precision.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/Precision.java
@@ -522,8 +522,8 @@
      * @return The number of orders of magnitude the input was adjusted by this method.
      */
     int chooseMultiplierAndApply(DecimalQuantity input, MultiplierProducer producer) {
-        // Do not call this method with zero.
-        assert !input.isZero();
+        // Do not call this method with zero, NaN, or infinity.
+        assert !input.isZeroish();
 
         // Perform the first attempt at rounding.
         int magnitude = input.getMagnitude();
@@ -532,7 +532,7 @@
         apply(input);
 
         // If the number rounded to zero, exit.
-        if (input.isZero()) {
+        if (input.isZeroish()) {
             return multiplier;
         }
 
@@ -603,7 +603,7 @@
             value.roundToMagnitude(getRoundingMagnitudeSignificant(value, maxSig), mathContext);
             value.setMinFraction(Math.max(0, -getDisplayMagnitudeSignificant(value, minSig)));
             // Make sure that digits are displayed on zero.
-            if (value.isZero() && minSig > 0) {
+            if (value.isZeroish() && minSig > 0) {
                 value.setMinInteger(1);
             }
         }
@@ -613,7 +613,7 @@
          * compatibility mode.
          */
         public void apply(DecimalQuantity quantity, int minInt) {
-            assert quantity.isZero();
+            assert quantity.isZeroish();
             quantity.setMinFraction(minSig - minInt);
         }
     }
@@ -744,7 +744,7 @@
         if (maxSig == -1) {
             return Integer.MIN_VALUE;
         }
-        int magnitude = value.isZero() ? 0 : value.getMagnitude();
+        int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
         return magnitude - maxSig + 1;
     }
 
@@ -756,7 +756,7 @@
     }
 
     private static int getDisplayMagnitudeSignificant(DecimalQuantity value, int minSig) {
-        int magnitude = value.isZero() ? 0 : value.getMagnitude();
+        int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
         return magnitude - minSig + 1;
     }
 }
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
index f195f6e..8246af9 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
@@ -5,6 +5,7 @@
 import java.text.Format.Field;
 
 import com.ibm.icu.impl.FormattedStringBuilder;
+import com.ibm.icu.impl.number.ConstantAffixModifier;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.MicroPropsGenerator;
@@ -162,9 +163,15 @@
             MicroProps micros = parent.processQuantity(quantity);
             assert micros.rounder != null;
 
+            // Do not apply scientific notation to special doubles
+            if (quantity.isInfinite() || quantity.isNaN()) {
+                micros.modInner = ConstantAffixModifier.EMPTY;
+                return micros;
+            }
+
             // Treat zero as if it had magnitude 0
             int exponent;
-            if (quantity.isZero()) {
+            if (quantity.isZeroish()) {
                 if (notation.requireMinInt && micros.rounder instanceof SignificantRounderImpl) {
                     // Show "00.000E0" on pattern "00.000E0"
                     ((SignificantRounderImpl) micros.rounder).apply(quantity,
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java
index 994ca99..d8aae25 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java
@@ -463,7 +463,7 @@
   }
 
   @Override
-  public boolean isZero() {
+  public boolean isZeroish() {
     if (primary == -1) {
       return fallback.compareTo(BigDecimal.ZERO) == 0;
     } else {
@@ -518,7 +518,7 @@
 
   @Override
   public int signum() {
-      return isNegative() ? -1 : isZero() ? 0 : 1;
+      return isNegative() ? -1 : isZeroish() ? 0 : 1;
   }
 
   private void setNegative(boolean isNegative) {
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
index e0ad131..e09cd03 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
@@ -177,6 +177,22 @@
                 ULocale.ENGLISH,
                 -1000000,
                 "-1E6");
+
+        assertFormatSingle(
+                "Scientific Infinity",
+                "scientific",
+                NumberFormatter.with().notation(Notation.scientific()),
+                ULocale.ENGLISH,
+                Double.NEGATIVE_INFINITY,
+                "-∞");
+
+        assertFormatSingle(
+                "Scientific NaN",
+                "scientific",
+                NumberFormatter.with().notation(Notation.scientific()),
+                ULocale.ENGLISH,
+                Double.NaN,
+                "NaN");
     }
 
     @Test
@@ -386,6 +402,22 @@
                 1e7,
                 "1000\u842C");
 
+        assertFormatSingle(
+                "Compact Infinity",
+                "compact-short",
+                NumberFormatter.with().notation(Notation.compactShort()),
+                ULocale.ENGLISH,
+                Double.NEGATIVE_INFINITY,
+                "-∞");
+
+        assertFormatSingle(
+                "Compact NaN",
+                "compact-short",
+                NumberFormatter.with().notation(Notation.compactShort()),
+                ULocale.ENGLISH,
+                Double.NaN,
+                "NaN");
+
         Map<String, Map<String, String>> compactCustomData = new HashMap<>();
         Map<String, String> entry = new HashMap<>();
         entry.put("one", "Kun");
@@ -1997,6 +2029,36 @@
     }
 
     @Test
+    public void signCoverage() {
+        // https://unicode-org.atlassian.net/browse/ICU-20708
+        Object[][][] cases = new Object[][][] {
+            { {SignDisplay.AUTO}, { "-∞", "-1", "-0", "0", "1", "∞", "NaN", "-NaN" } },
+            { {SignDisplay.ALWAYS}, { "-∞", "-1", "-0", "+0", "+1", "+∞", "+NaN", "-NaN" } },
+            { {SignDisplay.NEVER}, { "∞", "1", "0", "0", "1", "∞", "NaN", "NaN" } },
+            { {SignDisplay.EXCEPT_ZERO}, { "-∞", "-1", "-0", "0", "+1", "+∞", "NaN", "-NaN" } },
+        };
+        double negNaN = Math.copySign(Double.NaN, -0.0);
+        double inputs[] = new double[] {
+            Double.NEGATIVE_INFINITY, -1, -0.0, 0, 1, Double.POSITIVE_INFINITY, Double.NaN, negNaN
+        };
+        for (Object[][] cas : cases) {
+            SignDisplay sign = (SignDisplay) cas[0][0];
+            for (int i = 0; i < inputs.length; i++) {
+                double input = inputs[i];
+                String expected = (String) cas[1][i];
+                String actual = NumberFormatter.with()
+                    .sign(sign)
+                    .locale(Locale.US)
+                    .format(input)
+                    .toString();
+                assertEquals(
+                    input + " " + sign,
+                    expected, actual);
+            }
+        }
+    }
+
+    @Test
     public void decimal() {
         assertFormatDescending(
                 "Decimal Default",