読者です 読者をやめる 読者になる 読者になる

ITお絵かき修行

3歩歩いても忘れないために

LuhnアルゴリズムをJavaで書いた

カドカワ祭りで買った『プログラマの考え方がおもしろいほど身につく本』に載っていたLuhnアルゴリズムJavaで書いてみた。
Amazon.co.jp: カドカワ祭り: Kindleストア: 【ピックアップ】ライトノベル, 【ピックアップ】文芸, 【ピックアップ】実用・ビジネス・専門書, 【ピックアップ】コミック, 【ピックアップ】新書 など

後でエロい人が書いたコード*1を見ると、自分の糞コードっぷりがよくわかったが、後学のために晒す。

【お題】
元の数字の各桁に対して、1桁おきにその数字を2倍する。そのあとで、各桁の数字を足していく(2倍した結果2桁になる数字があれれば、十の位と一の位をそれぞれ個別に足す)。その合計が10で割り切れる場合、識別記号は妥当なものであるとみなす。

public class SampleLuhn {

	/**
	 * チェックサム値の取得
	 * @param total 各桁の総和
	 * @return チェックサム値
	 */
	private static int getCheckSum(int total) {
		int checkSum = 0;
		if(total % 10 != 0){
			checkSum = 10 - (total % 10);
		}
		return checkSum;
	}

	/**
	 * 引数の値を2倍した値を返却する(ただし2桁になった場合は各桁の数値を足した値を返却する)
	 * @param target 処理対象の数値
	 * @return 第一引数の値を2倍した値
	 */
	private static int doubleDigitValue(int target) {

		int doubleDigit = target * 2;

		if(doubleDigit >= 10){
			return 1 + doubleDigit % 10;
		}else {
			return doubleDigit;
		}
	}

	/**
	 * 第一引数の数値(偶数桁)における各桁の総和を返却する
	 * @param target 処理対象の数値
	 * @param length  処理対象の数値の桁数
	 * @param power 処理対象の数値の累乗
	 * @return 第一引数における各数字の総和
	 */
	private static int evenSum(int target, int length, int power) {

		// 総和
		int total = 0;

		for (int i = 1; i <= length; i++) {
			System.out.println(i + "桁目は" + (target / power));

			if(i%2 == 0){
				// 偶数桁読み込み時
				total += target / power;

			}else {
				// 奇数桁読み込み時
				int doubleVal= doubleDigitValue(target / power);
				total += doubleVal;
			}

			target %= power;
			power /= 10;
		}
		System.out.println("総和 : " + total);

		return total;
	}

	/**
	 * 第一引数の数値(奇数桁)における各桁の総和を返却する
	 * @param target 処理対象の数値
	 * @param length  処理対象の数値の桁数
	 * @param power 処理対象の数値の累乗
	 * @return 第一引数における各数字の総和
	 */
	private static int oddSum(int target, int length, int power) {

		// 総和
		int total = 0;

		for (int i = 1; i <= length; i++) {
			System.out.println(i + "桁目は" + (target / power));

			if(i%2 == 0){
				// 偶数桁読み込み時
				int doubleVal= doubleDigitValue(target / power);
				total += doubleVal;
			}else {
				// 奇数桁読み込み時
				total += target / power;

			}
			target %= power;
			power /= 10;
		}
		System.out.println("総和 : " + total);

		return total;
	}

	/**
	 * チェックサム値の取得
	 * @param target
	 * @return チェックサム値
	 */
	public static int createLohnCheckSum(int target) {

		// 桁数
		int length = String.valueOf(target).length();
		// 桁数に対する累乗
		int power = (int)Math.pow(10, length - 1);
		// 総和
		int sum = 0;

		// 桁数の偶数・奇数で場合分け
		if(length % 2 == 0){
			sum = evenSum(target, length, power);
		}else {
			sum = oddSum(target, length, power);
		}
		// チェックサム値取得
		int checkSum = getCheckSum(sum);

		return checkSum;
	}

	/**
	 * mainメソッド
	 * @param args
	 */
	public static void main(String[] args) {

		// チェック対象の数値
		int target = 12345;

		// チェックサム作成
		int checkSum = createLohnCheckSum(target);
		System.out.println("checksum : " + checkSum);

	}
}


ちなみに参照実装は下記。エレガントだった。
http://www.chriswareham.demon.co.uk/software/Luhn.java