質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

4回答

1465閲覧

IntegerのgetCharsの52429の意味

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

1グッド

0クリップ

投稿2018/03/03 16:21

編集2018/03/03 17:59

JavaのIntegerのgetCharsメソッドの52429の数字の意味が分かりません。
(※コードはjdk8から抜粋。)

Java

1static void getChars(int i, int index, char[] buf) { 2 int q, r; 3 int charPos = index; 4 char sign = 0; 5 6 if (i < 0) { 7 sign = '-'; 8 i = -i; 9 } 10 11 // Generate two digits per iteration 12 while (i >= 65536) { 13 q = i / 100; 14 // really: r = i - (q * 100); 15 r = i - ((q << 6) + (q << 5) + (q << 2)); 16 i = q; 17 buf [--charPos] = DigitOnes[r]; 18 buf [--charPos] = DigitTens[r]; 19 } 20 21 // Fall thru to fast mode for smaller numbers 22 // assert(i <= 65536, i); 23 for (;;) { 24 q = (i * 52429) >>> (16+3);//openjdk9 25 r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... 26 buf [--charPos] = digits [r]; 27 i = q; 28 if (i == 0) break; 29 } 30 if (sign != 0) { 31 buf [--charPos] = sign; 32 } 33 }

上記のコードの中にある、52429を導出する公式や原理を教えて頂きたいです。

Javaをご存知の方教えてください。

tatsuya6502👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2018/03/03 16:35 編集

そもそもこれはどこのメソッドで何をするメソッドなのですか?「IntegerのgetChars」ということですが、java.lang.Integerクラスにはこのようなメソッドは存在しません。
退会済みユーザー

退会済みユーザー

2018/03/03 17:02 編集

publicメソッドではないので、apiではありません。アクセスレベルもデフォルトです。そもそも、これがどこのメソッドでなにをするメソッドなのか分からないひとは、答えなくていいですよ。説明した所で答えられないでしょう。
guest

回答4

0

ベストアンサー

「10で割る」ではなく、「0.1を掛ける」と考えてみましょう。
さらにシフト演算を利用すべく、「整数を掛けてシフトする」という計算をします。
その際の誤差を小さくするため、最初に掛ける整数の有効数字の桁数なるべく多くとります。
この作業の段階で対象の数字は16ビット以下なので、16ビットまでの整数であれば、
掛けても(符号なし整数の範囲で)オーバーフローしないということになります。
なので、整数部を16ビット取るように0.1の二進表記を変形します。

十進数の0.1は二進法では0.00011001100110011001100...(2)なので、
0.00011001100110011001100...(2)
=0.11001100110011001100...(2)*2^-3 (小数首位まで0を指数表記に移す)
=1100110011001100.1100...(2)*2^-(3+16) (16ビットの有効数字を取るため16桁分指数に移す)
となります。「*2^-(3+16)」の部分は(3+16)ビットだけ右シフトと考えられるので、
1100110011001100(2)を掛けて19ビット下げれば、結果的に10で割ったことになります。
ただし、1100110011001100(2)では0.1倍に満たず、10の倍数などの場合は切り捨てが起きて
0.1倍より1小さい値が出てしまう可能性があります。
そのため掛ける数を1増やし、1100110011001101(2)にしているのでしょう。
これを10進数に直すと、52429になります。

投稿2018/03/03 17:14

編集2018/03/04 04:12
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 17:26

swordoneさん、ご丁寧にご回答ありがとうございます。 しかし、この答えは本質ではありません。 例えば、何故、16+3だけ、左シフトさせることにしたのでしょうか。 swordoneさんの解説では、16+2や16+1でも、いいことになってしまいます。 しかし、意図時に52429を選択し、結果的に16+3シフトさせることになったと考えています。 ですので、52429の導出過程を知りたいのです。 コードにも参考論文がかいてあります。 Division by Invariant Integers using Multiplication です。これを、必要な部分だけ抜き取り、公式だけでもいいのです。 どうか、教えてください。
swordone

2018/03/03 17:33

>例えば、何故、16+3だけ、左シフトさせることにしたのでしょうか。 誤差をなるべく小さくするためと考えます。誤差を小さくするには、掛ける数の有効数字の桁数を多く取ることです。 回答中にも書きましたが、掛ける対象の数は最高で16ビットの可能性があるため、符号なし整数の範囲で考えれば16ビットまでの掛け算であればオーバーフローせず計算できることになります。 その最大限の16ビットを有効数字として取るため、16+3だけシフトすることにしたのです。 16+2ビット(私としては3+15ビット)とした場合は有効数字が15ビットとなるため、精度が落ちます。
swordone

2018/03/03 17:38

最初に16ビット以下に抑える計算をしているのもおそらくこのためですね。 仮に17ビットの数で同じことをしようとすると、最大で15ビットの有効数字しか取れません。 掛け算によって16ビット目に誤差が生じるため、正確に10分の1できないのです。
退会済みユーザー

退会済みユーザー

2018/03/03 17:49

おかげ様で、大変良くわかりました。 腑に落ちました。 最後まで付き合って頂き ありがとうございます。 勉強になりました。 また、お願い致します。
guest

0

JDK 8までのIntegerクラスにて、
1994年の当時は有効であったであろう手動最適化コードです。

JDK-8136500にてコードの内容が修正済みです、openjdkのJava 9ではそのようなコードはなくなっています。

投稿2018/03/03 17:34

umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 18:04

親切に教えてくださり。ありがとうございます。 やはり、JVMが頭がよくなったからですかね。 aws Lambdaの実装中で、lambdaがJava8までしか対応していなく、 Java8のソースだということを忘れてしまってました。 質問を、ついでに修正しました。
guest

0

http://techtipshoge.blogspot.jp/2013/09/integergetchars.html
こういうことらしいですね。

投稿2018/03/03 16:35

Artz

総合スコア158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 16:45

この記事を理解されていたら、説明してくださいませんかね。 質問する前に、これ見たんですけど、理解できませんでした。
guest

0

オーバーフロー対策

int i,q; i = 30; q = (i * 52429) >>> (16+3); System.out.println(q); // 3 i = 323; q = (i * 52429) >>> (16+3); System.out.println(q); // 32 i = 3; q = (i * 52429) >>> (16+3); System.out.println(q); // 0

投稿2018/03/03 16:46

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 16:52 編集

オーバーフロー対策にはなっていないですよね。 間違いなく、パフォーマンスを意識したコードをかいています。 除算を乗算に直すさいに如何にして、 52429 を導いたのかがわからないのです。 教えてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問