/**
  * Converts the sensitivities in this instance to an equivalent in the specified currency.
  *
  * <p>Any FX conversion that is required will use rates from the provider.
  *
  * @param resultCurrency the currency of the result
  * @param rateProvider the provider of FX rates
  * @return the sensitivity object expressed in terms of the result currency
  * @throws RuntimeException if no FX rate could be found
  */
 @Override
 public CurveCurrencyParameterSensitivities convertedTo(
     Currency resultCurrency, FxRateProvider rateProvider) {
   List<CurveCurrencyParameterSensitivity> mutable = new ArrayList<>();
   for (CurveCurrencyParameterSensitivity sens : sensitivities) {
     insert(mutable, sens.convertedTo(resultCurrency, rateProvider));
   }
   return new CurveCurrencyParameterSensitivities(ImmutableList.copyOf(mutable));
 }
 // inserts a sensitivity into the mutable list in the right location
 // merges the entry with an existing entry if the key matches
 private static void insert(
     List<CurveCurrencyParameterSensitivity> mutable, CurveCurrencyParameterSensitivity addition) {
   int index =
       Collections.binarySearch(mutable, addition, CurveCurrencyParameterSensitivity::compareKey);
   if (index >= 0) {
     CurveCurrencyParameterSensitivity base = mutable.get(index);
     double[] combined =
         DoubleArrayMath.combineByAddition(base.getSensitivity(), addition.getSensitivity());
     mutable.set(index, base.withSensitivity(combined));
   } else {
     int insertionPoint = -(index + 1);
     mutable.add(insertionPoint, addition);
   }
 }
 /**
  * Checks if this sensitivity equals another within the specified tolerance.
  *
  * <p>This returns true if the two instances have the same keys, with arrays of the same length,
  * where the {@code double} values are equal within the specified tolerance.
  *
  * @param other the other sensitivity
  * @param tolerance the tolerance
  * @return true if equal up to the tolerance
  */
 public boolean equalWithTolerance(CurveCurrencyParameterSensitivities other, double tolerance) {
   List<CurveCurrencyParameterSensitivity> mutable = new ArrayList<>(other.sensitivities);
   // for each sensitivity in this instance, find matching in other instance
   for (CurveCurrencyParameterSensitivity sens1 : sensitivities) {
     // list is already sorted so binary search is safe
     int index =
         Collections.binarySearch(mutable, sens1, CurveCurrencyParameterSensitivity::compareKey);
     if (index >= 0) {
       // matched, so must be equal
       CurveCurrencyParameterSensitivity sens2 = mutable.get(index);
       if (!DoubleArrayMath.fuzzyEquals(
           sens1.getSensitivity(), sens2.getSensitivity(), tolerance)) {
         return false;
       }
       mutable.remove(index);
     } else {
       // did not match, so must be zero
       if (!DoubleArrayMath.fuzzyEqualsZero(sens1.getSensitivity(), tolerance)) {
         return false;
       }
     }
   }
   // all that remain from other instance must be zero
   for (CurveCurrencyParameterSensitivity sens2 : mutable) {
     if (!DoubleArrayMath.fuzzyEqualsZero(sens2.getSensitivity(), tolerance)) {
       return false;
     }
   }
   return true;
 }