All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.wnameless.math.NumberSystemConverter Maven / Gradle / Ivy

The newest version!
/**
 *
 * @author Wei-Ming Wu
 *
 *
 * Copyright 2015 Wei-Ming Wu
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.github.wnameless.math;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newLinkedHashSet;

import java.math.BigDecimal;
import java.util.List;
import java.util.Set;

import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.primitives.Chars;

/**
 * 
 * {@link NumberSystemConverter} converts any number from arbitrary number
 * system 1 to arbitrary number system 2.
* Ex: OCT to HEX.
*
* Each digit of either base can be self-defined freely. * */ public final class NumberSystemConverter { private final List base1; private final List base2; /** * Creates a number system converter. * * @param base1 * a List of each digit character in base 1, the 0-based order of * each digit is corresponding to its decimal value * @param base2 * a List of each digit character in base 2, the 0-based order of * each digit is corresponding to its decimal value */ public NumberSystemConverter(List base1, List base2) { checkNotNull(base1); checkNotNull(base2); checkArgument(base1.size() >= 2 && base2.size() >= 2, "All bases must include more than 2 digits."); checkArgument(!base1.contains(null) && !base2.contains(null), "All bases must NOT include null."); Set set1 = newLinkedHashSet(base1); Set set2 = newLinkedHashSet(base2); checkArgument(base1.size() == set1.size() && base2.size() == set2.size(), "All digits of a base must be unique."); List invalidChars = ImmutableList.of(' ', '-'); checkArgument( !Iterables.removeAll(set1, invalidChars) && !Iterables.removeAll(set2, invalidChars), "All digits of a base must NOT include whitespace ' ' or minus sign '-'."); this.base1 = ImmutableList.copyOf(base1); this.base2 = ImmutableList.copyOf(base2); } private void checkNoInvalidDigit(String base1Digits) { List inputChars = newArrayList(Chars.asList(base1Digits.toCharArray())); Iterables.removeAll(inputChars, base1); checkArgument(inputChars.size() == 0, "Input contains invalid digit."); } /** * Returns a decimal value of input base 1 number. * * @param base1Digits * any base 1 number * @return a decimal */ public BigDecimal toDecimal(String base1Digits) { checkNotNull(base1Digits); String input = base1Digits.replaceFirst("^- *", ""); boolean isNegtive = input.length() < base1Digits.length(); checkNoInvalidDigit(input); BigDecimal decimal = new BigDecimal(0); BigDecimal base = new BigDecimal(base1.size()); int exponent = 0; for (int i = input.length() - 1; i >= 0; i--) { BigDecimal pos = new BigDecimal(base1.indexOf(input.charAt(i))); decimal = decimal.add(pos.multiply(base.pow(exponent))); exponent++; } return isNegtive ? decimal.multiply(new BigDecimal(-1)) : decimal; } /** * Returns a base 2 number of input base 1 number. * * @param base1Digits * any base 1 number * @return a base 2 number */ public String toBase2(String base1Digits) { checkNotNull(base1Digits); String input = base1Digits.replaceFirst("^- *", ""); boolean isNegtive = input.length() < base1Digits.length(); checkNoInvalidDigit(input); StringBuilder outputNumberStr = new StringBuilder(); BigDecimal number = toDecimal(input); BigDecimal base = new BigDecimal(base2.size()); while (number.compareTo(base) >= 0) { BigDecimal[] qAndR = number.divideAndRemainder(base); BigDecimal quotient = qAndR[0]; BigDecimal remainder = qAndR[1]; outputNumberStr.insert(0, base2.get(remainder.intValue())); number = quotient; } outputNumberStr.insert(0, base2.get(number.intValue())); if (isNegtive) outputNumberStr.insert(0, '-'); return outputNumberStr.toString(); } @Override public int hashCode() { return Objects.hashCode(base1, base2); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (!(o instanceof NumberSystemConverter)) return false; NumberSystemConverter other = (NumberSystemConverter) o; return Objects.equal(base1, other.base1) && Objects.equal(base2, other.base2); } @Override public String toString() { return "A number system converter from Base1" + base1 + " to " + "Base2" + base2; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy