HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavaModerate

Convert IP address to its binary representation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
addressconvertitsbinaryrepresentation

Problem

For a recent lab at the university we had to match the longest prefix for an IP (v4) address by using a Trie data structure. The code works fine, but it takes about 2 minutes to load a 14 million-line routing table. I examined what was causing the slowness, and it was the (String) IP to (String) binary format conversion.

For example, the IP address 127.0.0.1 should be converted to 01111111000000000000000000000001. I my original method (slow) uses String.format, which I find much more readable and easy to follow. I then wrote a different method using a temporary char[], filled with '0' to use as padding.

The speedup of the fast method is about 6x. Below is a stripped down version for demonstration and measurement:

```
import java.util.Arrays;

public class Main {

public static void main(String[] args) {
final String ip = "127.0.0.1";
String binaryIp;
final long start = System.currentTimeMillis();

for (int i = 0; i < 10000000; i ++) {
binaryIp = fast(ip);
}

long fast = System.currentTimeMillis();

for (int i = 0; i < 10000000; i ++) {
binaryIp = slow(ip);
}

long slow = System.currentTimeMillis();

System.out.println("Fast time: " + (fast - start) + " ms");
System.out.println("Slow time: " + (slow - fast) + " ms");
}

public static String fast(String ip) {

StringBuilder bStringBuilder = new StringBuilder();
String ipParts[] = ip.split("\\.");

for (String ipPart : ipParts) {

String binString = Integer.toBinaryString(Integer.parseInt(ipPart));
int length = 8 - binString.length();
char[] padArray = new char[length];
Arrays.fill(padArray, '0');
bStringBuilder.append(padArray).append(binString);
}
System.out.println(bStringBuilder.toString());
return bStringBuilder.toString();
}

public static String slow(Strin

Solution

I don't have access to your test file, but try:

private static final String[] PAD_ZEROS= 
    new String[] {
        "00000000", 
        "0000000", 
        "000000", 
        "00000", 
        "0000", 
        "000", 
        "00", 
        "0", 
        ""
    };

   public static String fast(final String ip) {
        final StringBuilder result = new StringBuilder();
        final String octals[] = ip.split("\\.");
        for (final String octal: octals) {    
            final String binaryString = Integer.toBinaryString(Integer.parseInt(octal));
            result.append(PAD_ZEROS[binaryString.length()]);
            result.append(binaryString);
        }
        return result.toString();
    }


In general, I'd suggest avoiding hungarian notation (bStringBuilder), unnecessary abbreviations(binString), and magic numbers (if you keep the 8, it should be in a private static final class-level variable).

Note that your performance testing is flawed. The problem is the VM performs internal optimizations as it runs which can improve the performance of the system. You should test either fast or slow, but not both, in one execution. Don't test the same string over and over again, but pull in your routing file. Then, unless your whole application is to run this one method on the file and then stop, you should run for a while, throw out that data, then start measuring. Maybe do 2 executions of the file, but only time the second one. That imitates the method being called from a live system that's been running a while, instead of a cold system.

Two more things: as @rofl said, presize the StringBuilder. Also pull the System.out.println() out of your method - it's an artificial drag on the performance.

-- Working off of @rofl's other suggestion, this is 25% faster on my machine than your fast method, including the time to populate the map. It does consume more memory, and it eagerly maps numbers which may not be used. It is less elegant than @rofl's suggestion, and possibly slower, but I find it easier to read.

private static final String[] PAD_ZEROS =
        new String[] {
            "00000000",
            "0000000",
            "000000",
            "00000",
            "0000",
            "000",
            "00",
            "0",
            ""
        };

private static final Map MAP =
        new HashMap(256);

private static void populateMap() {
    for (int i = 0; i < 256; i++) {
        final String binaryString = Integer.toBinaryString(i);
        MAP.put(
            Integer.toString(i), 
            PAD_ZEROS[binaryString.length()] + binaryString);
    }
}

public static String faster(final String ip) {
    final StringBuilder result = new StringBuilder(32);
    final String octals[] = ip.split("\\.");
    for (final String octal: octals) {
        result.append(MAP.get(octal));
    }
    return result.toString();
}

Code Snippets

private static final String[] PAD_ZEROS= 
    new String[] {
        "00000000", 
        "0000000", 
        "000000", 
        "00000", 
        "0000", 
        "000", 
        "00", 
        "0", 
        ""
    };

   public static String fast(final String ip) {
        final StringBuilder result = new StringBuilder();
        final String octals[] = ip.split("\\.");
        for (final String octal: octals) {    
            final String binaryString = Integer.toBinaryString(Integer.parseInt(octal));
            result.append(PAD_ZEROS[binaryString.length()]);
            result.append(binaryString);
        }
        return result.toString();
    }
private static final String[] PAD_ZEROS =
        new String[] {
            "00000000",
            "0000000",
            "000000",
            "00000",
            "0000",
            "000",
            "00",
            "0",
            ""
        };

private static final Map<String, String> MAP =
        new HashMap<String, String>(256);

private static void populateMap() {
    for (int i = 0; i < 256; i++) {
        final String binaryString = Integer.toBinaryString(i);
        MAP.put(
            Integer.toString(i), 
            PAD_ZEROS[binaryString.length()] + binaryString);
    }
}

public static String faster(final String ip) {
    final StringBuilder result = new StringBuilder(32);
    final String octals[] = ip.split("\\.");
    for (final String octal: octals) {
        result.append(MAP.get(octal));
    }
    return result.toString();
}

Context

StackExchange Code Review Q#84376, answer score: 10

Revisions (0)

No revisions yet.