Using string vs byte[] as value, Memory usage in map - java

I read it in multiple places that using byte[] instead of string would save you memory. I wanted to test it out using jol.
Here my test:
public static void main (String[] args) throws java.lang.Exception{
System.out.println(VMSupport.vmDetails());
String StrByte = GraphLayout.parseInstance(sizeOfStrByteMap(100000)).toFootprint();
String ByteByte = GraphLayout.parseInstance(sizeOfByteByteMap(100000)).toFootprint();
String StrStr = GraphLayout.parseInstance(sizeOfStrStrMap(100000)).toFootprint();
System.out.println(StrByte);
System.out.println(ByteByte);
System.out.println(StrStr);
}
public static HashMap<String, String> sizeOfStrStrMap(int size) {
String value = "this is the sample value";
HashMap<String, String> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i), value);
}
return map;
}
public static HashMap<String, byte[]> sizeOfStrByteMap(int size) {
byte[] value = "this is the sample value".getBytes();
HashMap<String, byte[]> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i), value);
}
return map;
}
public static HashMap<byte[], byte[]> sizeOfByteByteMap(int size) {
byte[] value = "this is the sample value".getBytes();
HashMap<byte[], byte[]> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i).getBytes(), value);
}
return map;
}
Here is my result:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
// StrByteMap
java.util.HashMap#15327b79d footprint:
COUNT AVG SUM DESCRIPTION
1 184 184 [B
100000 31 3120000 [C
1 1048592 1048592 [Ljava.util.HashMap$Node;
100000 24 2400000 java.lang.String
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
300003 9768824 (total)
// ByteByteMap
java.util.HashMap#a9d12ad footprint:
COUNT AVG SUM DESCRIPTION
100001 24 2400184 [B
1 1048592 1048592 [Ljava.util.HashMap$Node;
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
200003 6648824 (total)
// StrStrMap
java.util.HashMap#716d90fad footprint:
COUNT AVG SUM DESCRIPTION
100001 31 3120344 [C
1 1048592 1048592 [Ljava.util.HashMap$Node;
100001 24 2400024 java.lang.String
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
300004 9769008 (total)
As you can see, memory usage between StrByteMap and StrStrMap is almost identical. Am I testing it wrong here?
UPDATE:
Please see #Amod Pandey's question below, I would also like to know why.

For Map test you are putting in the same value reference so it is not going to use much space. In the same way that you have a different key you need to make the values different or as you see, the choice of value type doesn't make much difference.

I find it strange.
// StrByteMap
java.util.HashMap#15327b79d footprint:
COUNT AVG SUM DESCRIPTION
1 184 184 [B
100000 31 3120000 [C
There is one instance of byte arrary and 100000 instances of char array. Which is 100001 char array in the StrStr case
// StrStrMap
java.util.HashMap#716d90fad footprint:
COUNT AVG SUM DESCRIPTION
100001 31 3120344 [C
So even if you have stored byte array the memory footprint is of char array!!
Another point is for ByteByte the the Avg size of byte array object is 24 which is less than byte array size of 184 (StrByteMap) and shouldn't the total count in all three cases be the same.

Related

Java: Sorting an array from least to greatest

This is my first question on the site. I am in a CS class and part of one of my assignments involved sorting the scores column of an array from least to greatest and printing out the array in its new least-to-greatest form. I cannot seem to get the scores from the array to do so, for whatever reason, and I am very confused as to why it will not work. If any of you could help me, that would be awesome. Thanks! Here is the array I am working with. The two columns are the id (on the left) and the score (on the right):
365 265
222 223
306 262
003 559
004 560
203 224
113 243
208 242
213 229
115 257
302 242
223 230
001 599
311 256
323 245
321 245
123 253
104 239
002 513
112 239
207 228
325 246
116 246
218 243
110 238
And here is my code so far:
import java.io.*;
import java.util.*;
public class RankingTestScoresDriver
{
public static void main(String args[])
{
System.out.println("ID Score");
File file = new File("prog408a.dat");
int[] id = new int[24];
int[] score = new int[24];
try
{
Scanner kbReader = new Scanner(file);
while (kbReader.hasNextInt())
{
for (int i = 0; i < 25; i++)
{
id[i] = kbReader.nextInt();
score[i] = kbReader.nextInt();
}
}
}
catch (Exception e)
{
}
//From here down is the part which is giving me trouble.
int max;
max = score[0];
int index;
int maxScoreIndex = 0;
for (int k = 0; k < 25; k++)
{
for (index = 0; index < score.length; index++)
{
if (score[index] > max)
{
max = score[index];
maxScoreIndex = index;
}
}
System.out.println(maxScoreIndex + " " + max);
score[maxScoreIndex] = ((-1)*(max));
}
}
}
Currently it is producing this as the output:
ID Score
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
The final output should be the scores of the array but in least-to-greatest order.
Any help would be greatly appreciated in helping me fix the bit of code I am struggling on.
You can write a class that implements Comparable to do it simple.
class Score implements Comparable<Score> {
private int id, score;
Score(int id, int score) {
this.id = id;
this.score = score;
}
#override
public int compareTo(Score o) {
return score - o.score;
}
}
then after you create an array of Score, you can use sort() method.
Score[] scores = /* put data */
Arrays.sort(scores);
will work
In the section where you are trying to sort, I'd recommend calling Arrays.sort() on your array like this:
Arrays.sort(score);
Once you have the array sorted, print out each element from the beginning using a loop of some kind:
for(int i = 0; i < 25; i++)
{
System.out.println(i + " " + score[i]);
}
That should do the trick for you. If you don't need a fancy new sorting algorithm, just use one that's already coded for you :)
You need to sort the array. Right now your code doesn't do it, it just keeps track of the biggest value.
I'm assuming you don't have to worry about execution time here. In other words, if the algorithm is going to take a long time to execute for a large input it doesn't matter to your professor.
There are many ways to sort an array. One way to do it called Bubble Sort. It is not very effective but will do the trick for you, and it's probably what your professor wants for now.
The idea is pretty simple: you discover the lowest value you hold on the entire array and swap the value with your current position. Imagine you have the following array:
[2, 4, 3, 5, 1]
Your current index is 0. You're going to go through the entire array to find the lowest value of them all. You will find out that the index 4, that holds the value 1 contains the lowest value. So you swap your current index (index 0, value 2). Now the array looks like this:
[1, 4, 3, 5, 2]
Now you move on to the next index, which is 1. You don't need to look at index 0 anymore since you already found out he is the lowest value and now you want the second lowest value. You do the same thing you did before: find the lowest value from index 1 to index 4 and swap them. You're going to do it until you get to the last index, where, you can guess by now, it will always be the biggest value.
Start by making sure you get the first value right. Once you get it, then move to the loop that iterates through the other values.
Working code : sort a two-dimensional array on column values in java.
Here we are using overloaded sort method in java.util.Arrays class which takes two arguments : the array to sort and a java.util.Comparator object.
import java.util.Arrays;
import java.util.Comparator;
public class SortArray {
Integer array[][] = { { 365, 265 }, { 222, 223 }, { 306, 262 },
{ 003, 559 }, { 004, 560 }, { 203, 224 }, { 113, 243 },
{ 208, 242 }, { 213, 229 }, { 115, 257 }, { 302, 242 },
{ 223, 230 }, { 001, 599 }, { 311, 256 }, { 323, 245 },
{ 321, 245 }, { 123, 253 }, { 104, 239 }, { 002, 513 },
{ 112, 239 }, { 207, 228 }, { 325, 246 }, { 116, 246 },
{ 218, 243 }, { 110, 238 } };
SortArray() {
System.out.println("Before sorting");
// show the contents of array
displayArray();
// sort array on score(second column)
Arrays.sort(array, new Comparator<Integer[]>() {
#Override
public int compare(Integer[] o1, Integer[] o2) {
Integer v1 = o1[1];
Integer v2 = o2[1];
// reverse sort on quantity
return v1.compareTo(v2);
}
});
// display array after sort
System.out.println("After sorting on score in ascending order");
displayArray();
}
public void displayArray() {
System.out.println("-------------------------------------");
System.out.println(" Index \t\t score");
for (int i = 0; i < array.length; i++) {
Integer[] sorted = array[i];
System.out.println(sorted[0] + "\t\t" + sorted[1]);
}
System.out.println("-------------------------------------");
}
public static void main(String[] args) {
new SortArray();
}
}
Explanation
A two dimensional array named array is created and initialized with default values.
First column of the array consists of Index values and second column is its Score.
For sorting the array, sort method of java.util.Arrays is used which takes 2 arguments : the array to be sorted and a java.util.Comparator object.
We pass an anonymous Comparator object(anonymous object means an object which has no name and which is created at its place of use only).
As 2d array in java is an array of arrays, thus, for sorting a 2d array on a column, we have to sort an integer array, therefore the generic type of this Comparator object should be Integer[ ].
Inside Comparator object, we implement its compare method which takes two objects of Integer[ ] type. These Integer objects represent the arrays to be compared.
For sorting the array on second column(score), the values at index 1 of the Integer[ ] objects are retrieved and compared.
Also read about Comparators and sort()
public static <T> void sort(T[] a,
Comparator<? super T> c)
Sorts the specified array of objects according to the order induced by the specified comparator. All elements in the array must be mutually comparable by the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the array).
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.
Implementation note: This implementation is a stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted, while offering the performance of a traditional mergesort when the input array is randomly ordered. If the input array is nearly sorted, the implementation requires approximately n comparisons. Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending order in its input array, and can take advantage of ascending and descending order in different parts of the the same input array. It is well-suited to merging two or more sorted arrays: simply concatenate the arrays and sort the resulting array.
The implementation was adapted from Tim Peters's list sort for Python ( TimSort). It uses techiques from Peter McIlroy's "Optimistic Sorting and Information Theoretic Complexity", in Proceedings of the Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, January 1993.
Parameters:
a - the array to be sorted
c - the comparator to determine the order of the array. A null value indicates that the elements' natural ordering should be used.

Java 8 hashmap high memory usage

I use a hashmap to store a QTable for an implementation of a reinforcement learning algorithm. My hashmap should store 15000000 entries. When I ran my algorithm I saw that the memory used by the process is over 1000000K. When I calculated the memory, I would expect it to use not more than 530000K. I tried to write an example and I got the same high memory usage:
public static void main(String[] args) {
HashMap map = new HashMap<>(16_000_000, 1);
for(int i = 0; i < 15_000_000; i++){
map.put(i, i);
}
}
My memory calulation:
Each entryset is 32 bytes
Capacity is 15000000
HashMap Instance uses: 32 * SIZE + 4 * CAPACITY
memory = (15000000 * 32 + 15000000 * 4) / 1024 = 527343.75K
Where I'm wrong in my memory calculations?
Well, in the best case, we assume a word size of 32 bits/4 bytes (with CompressedOops and CompressedClassesPointers). Then, a map entry consists of two words JVM overhead (klass pointer and mark word), key, value, hashcode and next pointer, making 6 words total, in other words, 24 bytes. So having 15,000,000 entry instances will consume 360 MB.
Additionally, there’s the array holding the entries. The HashMap uses capacities that are a power of two, so for 15,000,000 entries, the array size is at least 16,777,216, consuming 64 MiB.
Then, you have 30,000,000 Integer instances. The problem is that map.put(i, i) performs two boxing operations and while the JVM is encouraged to reuse objects when boxing, it is not required to do so and reusing won’t happen in your simple program that is likely to complete before the optimizer ever interferes.
To be precise, the first 128 Integer instances are reused, because for values in the -128 … +127 range, sharing is mandatory, but the implementation does this by initializing the entire cache on the first use, so for the first 128 iterations, it doesn’t create two instances, but the cache consists of 256 instances, which is twice that number, so we end up again with 30,000,000 Integer instances total. An Integer instance consist of at least the two JVM specific words and the actual int value, which would make 12 bytes, but due to the default alignment, the actually consumed memory will be 16 bytes, dividable by eight.
So the 30,000,000 created Integer instances consume 480 MB.
This makes a total of 360 MB + 64 MiB + 480 MB, which is more than 900 MB, making a heap size of 1 GB entirely plausible.
But that’s what profiling tools are for. After running your program, I got
Note that this tool only reports the used size of the objects, i.e. the 12 bytes for an Integer object without considering the padding that you will notice when looking at the total memory allocated by the JVM.
I sort of had the same requirement as you.. so decided to throw my thoughts here.
1) There is a great tool for that: jol.
2) Arrays are objects too, and every object in java has two additional headers: mark and klass, usually 4 and 8 bytes in size (this can be tweaked via compressed pointers, but not going to go into details).
3) Is is important to note about the load factor here of the map (because it influences the resize of the internal array). Here is an example:
HashMap<Integer, Integer> map = new HashMap<>(16, 1);
for (int i = 0; i < 13; ++i) {
map.put(i, i);
}
System.out.println(GraphLayout.parseInstance(map).toFootprint());
HashMap<Integer, Integer> map2 = new HashMap<>(16);
for (int i = 0; i < 13; ++i) {
map2.put(i, i);
}
System.out.println(GraphLayout.parseInstance(map2).toFootprint());
Output of this is different(only the relevant lines):
1 80 80 [Ljava.util.HashMap$Node; // first case
1 144 144 [Ljava.util.HashMap$Node; // second case
See how the size is bigger for the second case because the backing array is twice as big (32 entries). You can only put 12 entries in a 16 size array, because the default load factor is 0.75: 16 * 0.75 = 12.
Why 144? The math here is easy: an array is an object, thus: 8+4 bytes for headers. Plus 32 * 4 for references = 140 bytes. Due to memory alignment of 8 bytes, there are 4 bytes for padding resulting in a total 144 bytes.
4) entries are stored inside either a Node or a TreeNode inside the map (Node is 32 bytes and TreeNode is 56 bytes). As you use ONLY integers, you will have only Nodes, as there should be no hash collisions. There might be collisions, but this does not yet mean that a certain array entry will be converted to a TreeNode, there is a threshold for that. We can easily prove that there will be Nodes only:
public static void main(String[] args) {
Map<Integer, List<Integer>> map = IntStream.range(0, 15_000_000).boxed()
.collect(Collectors.groupingBy(WillThereBeTreeNodes::hash)); // WillThereBeTreeNodes - current class name
System.out.println(map.size());
}
private static int hash(Integer key) {
int h = 0;
return (h = key.hashCode()) ^ h >>> 16;
}
The result of this will be 15_000_000, there was no merging, thus no hash-collisions.
5) When you create Integer objects there is pool for them (ranging from -127 to 128 - this can be tweaked as well, but let's not for simplicity).
6) an Integer is an object, thus it has 12 bytes header and 4 bytes for the actual int value.
With this in mind, let's try and see the output for 15_000_000 entries (since you are using a load factor of one, there is no need to create the internal capacity of 16_000_000). It will take a lot of time, so be patient. I also gave it a
-Xmx12G and -Xms12G
HashMap<Integer, Integer> map = new HashMap<>(15_000_000, 1);
for (int i = 0; i < 15_000_000; ++i) {
map.put(i, i);
}
System.out.println(GraphLayout.parseInstance(map).toFootprint());
Here is what jol said:
java.util.HashMap#9629756d footprint:
COUNT AVG SUM DESCRIPTION
1 67108880 67108880 [Ljava.util.HashMap$Node;
29999872 16 479997952 java.lang.Integer
1 48 48 java.util.HashMap
15000000 32 480000000 java.util.HashMap$Node
44999874 1027106880 (total)
Let's start from bottom.
total size of the hashmap footprint is: 1027106880 bytes or 1 027 MB.
Node instance is the wrapper class where each entry resides. it has a size of 32 bytes; there are 15 million entries, thus the line:
15000000 32 480000000 java.util.HashMap$Node
Why 32 bytes? It stores the hashcode(4 bytes), key reference (4 bytes), value reference (4 bytes), next Node reference (4 bytes), 12 bytes header, 4 bytes padding, resulting in 32 bytes total.
1 48 48 java.util.HashMap
A single hashmap instance - 48 bytes for it's internals.
If you really want to know why 48 bytes:
System.out.println(ClassLayout.parseClass(HashMap.class).toPrintable());
java.util.HashMap object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 Set AbstractMap.keySet N/A
16 4 Collection AbstractMap.values N/A
20 4 int HashMap.size N/A
24 4 int HashMap.modCount N/A
28 4 int HashMap.threshold N/A
32 4 float HashMap.loadFactor N/A
36 4 Node[] HashMap.table N/A
40 4 Set HashMap.entrySet N/A
44 4 (loss due to the next object alignment)
Instance size: 48 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Next the Integer instances:
29999872 16 479997952 java.lang.Integer
30 million integer objects (minus 128 that are cached in the pool)
1 67108880 67108880 [Ljava.util.HashMap$Node;
we have 15_000_000 entries, but the internal array of a HashMap is a power of two size, that's 16,777,216 references of 4 bytes each.
16_777_216 * 4 = 67_108_864 + 12 bytes header + 4 padding = 67108880

Java, how to get a collection of byte from a byte array

This question may seems unique but I am having difficulties on solving it.
I have a byte array (a DW per row) and trying to get the byte value for every 9 bytes.
Here is how the byte array looks like:
0 1 2 3
4 5 6 7
8| 9 10 11
12 13 14 15
16 17| 18 19
20 21 22 23
24 25 26| 27
28 29 30 31
32 33 34 35|
.......
Here is a defined function that I need to use to get the value from the above patent:
getValue(int DWOffset, int highBit, int lowBit)
//DWOffset indicates the row of the data.
//highBit indicates the ending bit
//lowBit indicates the starting bit
My question is how to get every 9 bytes from the data (where the | appears) by using for loop? The data length can be found out by using
data.getLength(); //which returns the total number of bytes in the data
So far, I can get value on the first two row:
for(int i = 0; i < data.getLength()/(4*2); i++){
getValue(i*2, 31, 0); //DW i
getValue(i*2 + 1, 31, 0); //DW i+1
}
Part of the problem is that you seem to be mixing paradigms, conceptually looking at it as both a 2-dimensional and a 1-dimensional array. Looking at it as 2-dimensional, you need a getValue(int row, int column) that returns a single byte. Then you can do something like this:
final int TOTAL_BYTES_TO_INCLUDE = 9;
byte[] byteArray[] = new byte[TOTAL_BYTES_TO_INCLUDE];
int arrayIndex = 0;
for (int r = 0; r++; r < number_of_rows) {
for (int c = 0; c++; c < 4) {
byteArray[arrayIndex++] = getValue(r, c);
if (arrayIndex >= TOTAL_BYTES_TO_INCLUDE) {
... do something with your byte array ...
arrayIndex = 0;
}
}
}
There's some corner cases to deal with, like what happens if the number of available values is not a multiple of 9, what happens. What happens if the value read in causes byte-overflow. I don't reinitialize the array before each iteration, but is there any risk to something being left behind.

How much memory I'll get If I'll run my code?

What size of memory I will get if I will run this code?
List<Long> list = new LinkedList<>();
for (long i = 0; i < 4_000_000_000L; i++) {
list.add(i);
}
8Gb?
Such questions can be answered using the Java Object Layout tool. Here's the test code:
import org.openjdk.jol.info.GraphLayout;
import org.openjdk.jol.util.VMSupport;
import java.util.*;
public class JOLTest {
public static void main(String[] args) throws Exception {
List<Long> list = new LinkedList<>();
for (long i = 0; i < 4000L; i++) {
list.add(i);
if((i+1) % 1000 == 0) {
System.out.println("i = "+(i+1));
System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
}
}
}
I have not enough memory to check 4_000_000_000 entries, but it's not necessary as LinkedList memory allocation is linear:
i = 1000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
1000 24 24000 java.lang.Long
1 32 32 java.util.LinkedList
1000 24 24000 java.util.LinkedList$Node
2001 48032 (total)
i = 2000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
2000 24 48000 java.lang.Long
1 32 32 java.util.LinkedList
2000 24 48000 java.util.LinkedList$Node
4001 96032 (total)
i = 3000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
3000 24 72000 java.lang.Long
1 32 32 java.util.LinkedList
3000 24 72000 java.util.LinkedList$Node
6001 144032 (total)
i = 4000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
4000 24 96000 java.lang.Long
1 32 32 java.util.LinkedList
4000 24 96000 java.util.LinkedList$Node
8001 192032 (total)
So you practically have (48*n+32) bytes spent for n elements in the list, of which 24*n is Long instance, 24*n is internal LinkedList$Node instance and 32 is LinkedList itself. Thus the answer on your question would be 192_000_000_032 bytes... But this test was performed for small (<32Gb) -Xmx value when compressed oops work. For bigger amounts the numbers are different:
$ java -Xmx32G -cp test-1.0.jar JOLTest
i = 1000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
1000 24 24000 java.lang.Long
1 48 48 java.util.LinkedList
1000 40 40000 java.util.LinkedList$Node
2001 64048 (total)
i = 2000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
2000 24 48000 java.lang.Long
1 48 48 java.util.LinkedList
2000 40 80000 java.util.LinkedList$Node
4001 128048 (total)
i = 3000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
3000 24 72000 java.lang.Long
1 48 48 java.util.LinkedList
3000 40 120000 java.util.LinkedList$Node
6001 192048 (total)
i = 4000
java.util.LinkedList#41a4555ed footprint:
COUNT AVG SUM DESCRIPTION
4000 24 96000 java.lang.Long
1 48 48 java.util.LinkedList
4000 40 160000 java.util.LinkedList$Node
8001 256048 (total)
Thus in your case it's actually (64*n+48) bytes, namely 256_000_000_048 (roughly 256Gb).
Note that the results were obtained on Oracle JDK 1.8.0_40. It's not guaranteed that different JDK/JVM will produce the same result.
Also please note that normally Java collections cannot fit more than Integer.MAX_VALUE elements as size is stored in int. Looking into LinkedList implementation you can see that (assuming that you have enough memory) you will get no exception, but the size will silently overflow, thus probably it would be hard to work with this collection after that.

Java Code Integer Output

I am trying to write a code which raises 2 to
the powers of 0, 1, 2. 3. 4, .... n
For example for 31 it would reproduce the following results:
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192
16384 32768 65536 131072 262144 524288 1048576 2097152
4194304 8388608 16777216 33554432 67108864 134217728
268435456 536870912 1073741824 2147483648
I have written the following code:
public class Powersof2 {
public static void printPowersOf2(int n) {
if (n >= 0 && n <= 64) {
for (int i = 0 ; i <= n ; i++) {
System.out.print( Math.pow(2, i) + " ");
}
} else {
System.out.println("You have input an invalid value");
return;
}
}
public static void main(String[] args) {
printPowersOf2(31);
System.out.println();
}
}
However, it produces the following result instead:
1.0 2.0 4.0 8.0 16.0 32.0 64.0 128.0 256.0 512.0
1024.0 2048.0 4096.0 8192.0 16384.0 32768.0 65536.0
131072.0 262144.0 524288.0 1048576.0 2097152.0 4194304.0
8388608.0 1.6777216E7 3.3554432E7 6.7108864E7 1.34217728E8
2.68435456E8 5.36870912E8 1.073741824E9 2.147483648E9
How can I fix that?
Also I have another question
When I input larger values for n such as 62 the values start to be the same. For example 62 gives:
1 2 4 8 16 32 64 128 256 512 1024 2048 4096
8192 16384 32768 65536 131072 262144 524288 1048576
2097152 4194304 8388608 16777216 33554432 67108864 134217728
268435456 536870912 1073741824 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
2147483647 2147483647 2147483647 2147483647 2147483647
how can I fix this issue?
Since Math.pow returns a double while you are looking for an integer, consider using a simple bit trick for raising 2 to power n like this:
1L << n
The reason behind this trick is the same as that behind multiplying by powers of ten in the decimal system by writing additional zeros after the number.
This works for ns between 0 and 63, and produce a long:
for (int i = 0 ; i <= n ; i++) {
System.out.print( (1L << i) + " ");
}
Math.pow() always returns doubles. You need to cast it to an int. System.out.print((int)Math.pow(2, i)+ " ");
Because public static double pow(double a, double b) return a double. And Java double is 64 bit IEE754 number with precision, so you see the decimal points in the end.
You can cast it to int as (int)Math.pow(2, i)but be aware that for 2^31 onwards you will not get expected results because int range is from -2^31 to +2^31.
** First Solution:**
So, to get your expected result to get power up to 63, cast to long because Java long has range from -2^63 to +2^63
for (int i = 0; i <= 64; i++) {
System.out.println((long)Math.pow(2, i));
}
You query about result as so many 2147483647 :
This is called as Narrowing, when a bigger container value is casted to smaller container value.
Below excerpt from Java Language Specification - $5.1.3 Narrowing Primitive Conversion, for rules governing primitive narrowing.
So, after power of 31, all the higher bits (32, 33....) are discarded, and hence you always result of 31 bits i.e. 2^31.
In you case, as per JLS, your "integral type T" was int, so all bits are discarded but the n lowest order bits (which means 31, because you are narrowing to int)
A narrowing conversion of a signed integer to an integral type T
simply discards all but the n lowest order bits, where n is the number
of bits used to represent type T. In addition to a possible loss of
information about the magnitude of the numeric value, this may cause
the sign of the resulting value to differ from the sign of the input
value.
A comprehensive solution: (as per discussion going around)
Primitive data types has range limitation, so there are BigInteger, BigDecimal which provides arbitrarily long values and precision. So, you can use BigInteger to get accurate result.
Notice that if you Java's long then for 2^63 you get result as 9223372036854775807 while as per Power of two Wiki result should be 9223372036854775808 which you get when you use BigInteger
Bottom line: Use BigInteger to get desired range of power of 2.
Hope this covers all your concern and give you scalable solution.
for (int i = 0; i <= 64; i++) {
//System.out.println((long)Math.pow(2, i));
System.out.println(BigInteger.valueOf(2).pow(i)); //Gives exact result as per Wiki information
}
These are the powers of 2 through 2^31, just in the default output format of a double. With lower values, it will append .0, and with higher values, it's in pseudo-scientific notation. E.g. 1.6777216E7 means 1.677216 x 107, or 1,677,216. The double is returned from Math.pow.
You may find an integer type data type better formatted for your purpose. Use long, because int isn't quite big enough to store 2^31.
long product = 1;
for (int i = 0 ; i <= n ; i++)
{
System.out.print( product + " ");
product *= 2; // Equivalent: product <<= 1;
}
i could have used below code part, instead math.pow() , i am always scared of type conversion
int num=1;
for(int i=0;i<n;i++){
System.out.println(num);
num=num*2;
}
but as suggested it can not go beyond 31 . it is limit of int data type. try BigInteger if you want to print more
With Java 8 you can simply use the following stream:
IntStream.range(0, 32)
.map(value -> 1 << value)
.forEach(value -> System.out.println("value = " + value));
Also, the same is applicable to LongStream.

Categories