Return-Path: Delivered-To: apmail-harmony-commits-archive@www.apache.org Received: (qmail 71110 invoked from network); 31 Jan 2007 08:38:27 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 31 Jan 2007 08:38:27 -0000 Received: (qmail 94094 invoked by uid 500); 31 Jan 2007 08:38:32 -0000 Delivered-To: apmail-harmony-commits-archive@harmony.apache.org Received: (qmail 94076 invoked by uid 500); 31 Jan 2007 08:38:32 -0000 Mailing-List: contact commits-help@harmony.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@harmony.apache.org Delivered-To: mailing list commits@harmony.apache.org Received: (qmail 94067 invoked by uid 99); 31 Jan 2007 08:38:32 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 Jan 2007 00:38:32 -0800 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO brutus.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 Jan 2007 00:38:25 -0800 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id D5AD77142B5 for ; Wed, 31 Jan 2007 00:38:05 -0800 (PST) Message-ID: <22202889.1170232685871.JavaMail.jira@brutus> Date: Wed, 31 Jan 2007 00:38:05 -0800 (PST) From: "Alexey Petrenko (JIRA)" To: commits@harmony.apache.org Subject: [jira] Resolved: (HARMONY-3086) [math] poor hashCode in java.math.BigDecimal and java.math.BigDecimal In-Reply-To: <31567249.1170164553430.JavaMail.jira@brutus> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org [ https://issues.apache.org/jira/browse/HARMONY-3086?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Alexey Petrenko resolved HARMONY-3086. -------------------------------------- Resolution: Fixed The patch has been committed. Evgeniya, please verify. > [math] poor hashCode in java.math.BigDecimal and java.math.BigDecimal > --------------------------------------------------------------------- > > Key: HARMONY-3086 > URL: https://issues.apache.org/jira/browse/HARMONY-3086 > Project: Harmony > Issue Type: Improvement > Components: Classlib > Environment: Platform independent > Reporter: Evgeniya Maenkova > Assigned To: Alexey Petrenko > Attachments: HashMapTest.java, math.patch, math.patch, math.patch > > > As BigDecimal/BigInteger.hashCode isn't specified I belive we can do some improvements in this arrea. > 1)BigInteger.hashCode computes a hash code accordingly to the latest digit only. We could take all digits into account. > 2)BigDecimal.hashCode uses shift, so BigInteger's hashCode has pretty small influence on BigDecimal's hashCode. > public int hashCode() { > /* Take the 24 trailing bits of BigInteger hashcode > * and the 8 trailing bits of scale. */ > return ((getUnscaledValue().hashCode() << 24) | (0xFF & scale)); > } > 3) when we are dealing with "small" BigDecimal I believe it's possible to compute hash code more effectively without redudant objects creation (I mean BigInteger). > 4) I've written minimal test case with "big" BigDecimal as keys in some hashMap(to be attached, and see please below) and there the results (my laptop :), pretty approximately, of course): > RI: > -- > different hash coodes: 45000 > time6173 > -- > current java.math: > different hash coodes: 906 > time82239 > --patched java.math: > different hash coodes: 45000 > time6344 > (This test shows so big difference in time and hash code distribution. > 5)I get 1 failed test with this patch:org.apache.harmony.tests.java.math.BigIntegerHashCodeTest. Test is looking doubtful as (a) hash code isn;t specified so we shouldn't require this behavior; (b) It fails on RI also. So I would propose to remove this test at all. > - public void testUnequalObjectsEqual() { > - byte aBytes[] = {56, 100, -2, -76, 98, 54, 19, 3, -15, 45, 89, -111, 69, 103, 8, -9}; > - byte bBytes[] = {56, 100, -2, -76, 89, 45, 91, 3, -15, 45, 89, -111, 69, 103, 8, -9}; > - int aSign = 1; > - BigInteger aNumber = new BigInteger(aSign, aBytes); > - BigInteger bNumber = new BigInteger(aSign, bBytes); > - int code1 = aNumber.hashCode(); > - int code2 = bNumber.hashCode(); > - if (!aNumber.equals(bNumber)) { > - assertTrue("hash codes for these unequal objects should be equal", code1 == code2); > - } > - } > + } > Test case mentioned above: > ---- > import java.math.BigDecimal; > import java.text.NumberFormat; > import java.util.Arrays; > import java.util.HashMap; > import java.util.Random; > public class HashMapTest { > static class MyBigDecimal extends BigDecimal { > public MyBigDecimal(String s) { > super(s); > } > static long hashCodeCallsCounter; > static long equalsCallsCounter; > @Override > public int hashCode() { > hashCodeCallsCounter ++; > return super.hashCode(); > } > > @Override > public boolean equals(Object arg0) { > equalsCallsCounter ++; > return super.equals(arg0); > } > > static void reset() { > equalsCallsCounter = 0; > hashCodeCallsCounter = 0; > } > } > > > static MyBigDecimal[][][] keys; > static int[] hashcodes; > public static HashMap createRatesMap(int dim1, int dim2, > int dim3, BigDecimal value1) { > HashMap map = new HashMap(); > keys = new MyBigDecimal[dim1][dim2][dim3]; > StringBuffer sb = new StringBuffer(); > NumberFormat nf = NumberFormat.getNumberInstance(); > nf.setMinimumIntegerDigits(3); > hashcodes = new int[dim1 * dim2 * dim3]; > int ind = 0; > for (int i = 0; i < dim1; i ++){ > for (int j = 0; j < dim2; j ++) { > for (int k = 0; k < dim3; k ++) { > long res = i * 10000 + j * 100 + k; > int scale = 3 + ((i + j + k) % 5); > MyBigDecimal key = new MyBigDecimal(res + "." + res); > keys[i][j][k] = key; > hashcodes[ind ++] = key.hashCode(); > map.put(key, value1.setScale(scale, BigDecimal.ROUND_DOWN)); > } > } > } > return map; > } > > public static void main(String[] args) { > HashMap map = createRatesMap(300, 10, 15, BigDecimal.ONE); > Arrays.sort(hashcodes); > int currentValue = 0; > int currentIndex = 0; > int curLength = 0; > int[] value = new int[hashcodes.length]; > int[] counters = new int[hashcodes.length]; > > for (int i = 0; i < hashcodes.length; i ++) { > if (hashcodes[i] == currentValue) { > currentIndex++; > counters[curLength - 1] = currentIndex; > } else { > currentIndex = 1; > currentValue = hashcodes[i]; > value[curLength] = currentValue; > counters[curLength] = 1; > curLength++; > } > } > > MyBigDecimal.reset(); > Random random = new Random(); > long start = System.currentTimeMillis(); > for (int i = 0; i < 10000000; i ++) { > map.get(keys[random.nextInt(300)][random.nextInt(10)][random.nextInt(15)]); > } > System.out.println("different hash coodes: " + curLength); > System.out.println("time" + (System.currentTimeMillis() - start)); > > } > } -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.