Skip to content

Commit b91b1e7

Browse files
committed
Bits representation of a byte added
Comments refactoring.
1 parent 8435335 commit b91b1e7

File tree

7 files changed

+172
-8
lines changed

7 files changed

+172
-8
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ To distinguish bad habits, benchmarking against the compiler performance is ofte
1010
- Don't bother to use anything but the len() to get the [size of an array](./src/lenarray/README.md)
1111
- Don't duplicate code to handle the [first item of a list](./src/firstitem/README.md)
1212
- Don't try to [keep a single exit](./src/singleexit/README.md)
13-
- Always use [shadowing inside a for loop](./src/isvalid/README.md) even for a boolean
14-
- Don't bother about [irrelevant cases](./src/switch/README.md) in a switch
15-
- Use [bit masking](./src/bitorif/README.md) instead of a second if
13+
- Always use [shadowing inside a for loop](./src/isvalid/README.md) even for a boolean.
14+
- Don't bother about [irrelevant cases](./src/switch/README.md) in a switch.
15+
- Use [bit masking](./src/bitorif/README.md) instead of a second if.
16+
- Get the [bits representation of a byte](./src/bytetobits/README.md) using bits package is simple and efficient.
1617

1718
***Math***
1819
- math.Log2() is the most efficient to check that 2 is the [sole divisor](./src/switch/README.md).
1920

2021
***Arrays***
2122
- [Array of struct](./src/arraysstruct/README.md) is as efficient as multiple arrays.
2223
- [Array initialization](./src/arrayinit/README.md) using append is costly.
24+
- Using a method is marginally more efficient to [add an element to an array](./src/arrayofarray/README.md).
2325

2426
***Templates***
2527
- Use [implicit parsing for forms](src/formparse/README.md)
@@ -28,7 +30,7 @@ To distinguish bad habits, benchmarking against the compiler performance is ofte
2830
***Buffers***
2931
- No difference when [writing to file](src/tofile/README.md)
3032
- [Returning a buffer](src/returnbuffer/README.md) as a string is marginally more expensive.
31-
- Package io is much more efficient than fmt which offers many more possibilities:
33+
- Package `io` is much more efficient than `fmt` which offers many more possibilities:
3234
- [write a simple string](src/writestring/README.md).
3335
- [write a buffer to a buffer](src/writebuffer/README.md).
3436
- When handling every byte of a buffer, [use ReadByte](src/readbyte/README.md).

src/bytetobits/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Get bit representation of a byte
2+
3+
When based on strings, `%b` directive of the `fmt` package provides a bit display.
4+
But it requires to range on chars which is prohibitive compared to other methods.
5+
6+
Rotating the bits each time introduces some penalty.
7+
8+
The simplest code is using the `bits` package and is marginally more efficient.
9+
10+
`src>go test -bench=. ./bytetobits`
11+
12+
**Results**
13+
14+
```
15+
go version go1.13 windows/amd64
16+
17+
pkg: github.com/iWdGo/GoCompilerEfficiency/src/bytetobits
18+
BenchmarkRangeToBits-4 2522445 472 ns/op
19+
BenchmarkBits-4 11327166 101 ns/op
20+
BenchmarkAndToBits-4 13191872 93.4 ns/op
21+
BenchmarkBitsToBits-4 12252073 90.8 ns/op
22+
PASS
23+
```
24+
25+
26+
27+

src/bytetobits/bitstobytes.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math/bits"
6+
)
7+
8+
// fmt package and %b directive.
9+
// strings.SplitN has no use as []string is returned.
10+
func rangeToBits(data []byte) (st []int) {
11+
st = make([]int, len(data)*8) // Performance x 2 as no append occurs
12+
for i, d := range data {
13+
// Sprintf is overkill as you get 48 (0) and 49 (1)
14+
for j, c := range fmt.Sprintf("%08b", d) {
15+
if c == 48 { // "0"
16+
st[i*8+j] = 0
17+
} else {
18+
st[i*8+j] = 1
19+
}
20+
}
21+
}
22+
return
23+
}
24+
25+
// Isolating each bit in one rotation.
26+
func forToBits(bs []byte) []int {
27+
r := make([]int, len(bs)*8)
28+
for i, b := range bs {
29+
for j := 0; j < 8; j++ {
30+
r[i*8+j] = int(b >> uint(7-j) & 0x01)
31+
}
32+
}
33+
return r
34+
}
35+
36+
// Using and operation to isolate the bit and no rotation.
37+
func andToBits(data []byte) (st []int) {
38+
st = make([]int, len(data)*8) // Performance x 2 as no append occurs.
39+
var j uint
40+
exp := 0
41+
for i, d := range data {
42+
exp = 0
43+
j = 256 // 2 with exponent 8 to get leftmost bit first.
44+
for exp < 8 {
45+
j /= 2
46+
if b := uint(d) & j; b == j {
47+
st[i*8+exp] = 1
48+
} else {
49+
st[i*8+exp] = 0
50+
}
51+
exp += 1
52+
}
53+
}
54+
return
55+
}
56+
57+
// Using the bits package and a rotation.
58+
func bitsToBits(data []byte) (st []int) {
59+
st = make([]int, len(data)*8) // Performance x 2 as no append occurs.
60+
for i, d := range data {
61+
for j := 0; j < 8; j++ {
62+
if bits.LeadingZeros8(d) == 0 {
63+
// No leading 0 means that it is a 1
64+
st[i*8+j] = 1
65+
} else {
66+
st[i*8+j] = 0
67+
}
68+
d = d << 1
69+
}
70+
}
71+
return
72+
}

src/bytetobits/bitstobytes_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
import "testing"
4+
5+
var (
6+
data = []byte{3, 255}
7+
res = []int{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
8+
)
9+
10+
func arrayCompare(a1, a2 []int) bool {
11+
for i, a := range a1 {
12+
if a != a2[i] {
13+
return false
14+
}
15+
}
16+
return true
17+
}
18+
19+
func TestBits(t *testing.T) {
20+
if d := forToBits(data); !arrayCompare(d, res) {
21+
t.Errorf("got %v, want %v", d, res)
22+
}
23+
}
24+
25+
func TestRangeToBits(t *testing.T) {
26+
if d := rangeToBits(data); !arrayCompare(d, res) {
27+
t.Errorf("got %v, want %v", d, res)
28+
}
29+
}
30+
31+
func TestRangeAndToBits(t *testing.T) {
32+
if d := andToBits(data); !arrayCompare(d, res) {
33+
t.Errorf("got %v, want %v", d, res)
34+
}
35+
}
36+
37+
func TestRangeBitsToBits(t *testing.T) {
38+
if d := bitsToBits(data); !arrayCompare(d, res) {
39+
t.Errorf("got %v, want %v", d, res)
40+
}
41+
}
42+
43+
func BenchmarkBits(b *testing.B) {
44+
for n := 0; n < b.N; n++ {
45+
forToBits(data)
46+
}
47+
}
48+
49+
func BenchmarkRangeToBits(b *testing.B) {
50+
for n := 0; n < b.N; n++ {
51+
rangeToBits(data)
52+
}
53+
}
54+
55+
func BenchmarkAndToBits(b *testing.B) {
56+
for n := 0; n < b.N; n++ {
57+
andToBits(data)
58+
}
59+
}
60+
61+
func BenchmarkBitsToBits(b *testing.B) {
62+
for n := 0; n < b.N; n++ {
63+
bitsToBits(data)
64+
}
65+
}

src/writebuffer/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# Elementary write of a buffer to a buffer
22

33
The target is of type *buffer.Bytes and the `buffer` is simply written to it.
4-
An elementary case is considered. Any formatting or processing makes this benchmark irrelevant.
5-
This module is using methods writing a `buffer` without conversion.
64
- `fmt.Fprint`
75
- `Write()` method of buffer package with a conversion to `bytes`
86
- `WriteTo()` method of buffer package

src/writestring/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ go version go1.12.6 windows/amd64
1818
pkg: github.com/iWdGo/GoCompilerEfficiency/src/writestring
1919
BenchmarkFmtWriteString-4 1000000 1885 ns/op
2020
BenchmarkIoWriteString-4 2000000 694 ns/op
21-
BenchmarkBufferWriteTo-4 3000000 447 ns/op
21+
BenchmarkBufferWriteString-4 3000000 447 ns/op
2222
PASS
2323
```
2424

src/writestring/writestring_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func BenchmarkIoWriteString(b *testing.B) {
4141
}
4242
}
4343

44-
func BenchmarkBufferWriteTo(b *testing.B) {
44+
func BenchmarkBufferWriteString(b *testing.B) {
4545
for n := 0; n < b.N; n++ {
4646
i := bufferWriteString(s).Len()
4747
if i != len(s)*len(s) {

0 commit comments

Comments
 (0)