-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into cl/update-android-integration-tests
- Loading branch information
Showing
12 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Miscellaneous | ||
*.class | ||
*.log | ||
*.pyc | ||
*.swp | ||
.DS_Store | ||
.atom/ | ||
.buildlog/ | ||
.history | ||
.svn/ | ||
migrate_working_dir/ | ||
|
||
# IntelliJ related | ||
*.iml | ||
*.ipr | ||
*.iws | ||
.idea/ | ||
|
||
# The .vscode folder contains launch configuration and tasks you configure in | ||
# VS Code which you may wish to be included in version control, so this line | ||
# is commented out by default. | ||
#.vscode/ | ||
|
||
# Flutter/Dart/Pub related | ||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. | ||
/pubspec.lock | ||
**/doc/api/ | ||
.dart_tool/ | ||
.packages | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Substrate Fixed | ||
|
||
Implements substrate fixed support for some unsigned fixed point types. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
include: package:very_good_analysis/analysis_options.3.1.0.yaml | ||
|
||
linter: | ||
rules: | ||
public_member_api_docs: false | ||
lines_longer_than_80_chars: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const unsupportedNegativeValuesMsg = 'Negative values are not supported yet'; | ||
|
||
class FixedPointException implements Exception { | ||
const FixedPointException(this.message); | ||
|
||
factory FixedPointException.unsupportedNegativeValues() => const FixedPointException(unsupportedNegativeValuesMsg); | ||
|
||
final String message; | ||
|
||
@override | ||
String toString() { | ||
return 'FixedPointException: $message'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import 'package:ew_substrate_fixed/src/fixed_point_util.dart' show u16F16Util, u32F32Util, u64F64Util; | ||
|
||
abstract class FixedPoint { | ||
FixedPoint(this._bits); | ||
|
||
final BigInt _bits; | ||
|
||
BigInt get bits => _bits; | ||
|
||
double asDouble(); | ||
} | ||
|
||
class U16F16 extends FixedPoint { | ||
U16F16(super.bits); | ||
|
||
@override | ||
double asDouble() { | ||
return u16F16Util.toDouble(_bits); | ||
} | ||
} | ||
|
||
class U32F32 extends FixedPoint { | ||
U32F32(super.bits); | ||
|
||
@override | ||
double asDouble() { | ||
return u32F32Util.toDouble(_bits); | ||
} | ||
} | ||
|
||
class U64F64 extends FixedPoint { | ||
U64F64(super.bits); | ||
|
||
@override | ||
double asDouble() { | ||
return u64F64Util.toDouble(_bits); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import 'package:ew_substrate_fixed/src/parse_fixed_point.dart' as pf; | ||
import 'package:ew_substrate_fixed/src/to_fixed_point.dart' as tf; | ||
|
||
const u16F16Util = FixedPointUtil(BitCount(16, 16)); | ||
const u32F32Util = FixedPointUtil(BitCount(32, 32)); | ||
const u64F64Util = FixedPointUtil(BitCount(64, 64)); | ||
|
||
/// Util class that allows to have consts knowing how to handle | ||
/// fixed point numbers. | ||
class FixedPointUtil<T extends BitCount> { | ||
const FixedPointUtil(this.bitCount); | ||
|
||
final T bitCount; | ||
|
||
BigInt toFixed(double value) { | ||
return tf.toFixedPoint(value, integerBitCount: bitCount.integer, fractionalBitCount: bitCount.fractional); | ||
} | ||
|
||
double toDouble(BigInt value) { | ||
return pf.parseFixedPoint(value, integerBitCount: bitCount.integer, fractionalBitCount: bitCount.fractional); | ||
} | ||
} | ||
|
||
class BitCount { | ||
const BitCount(this._integerBitCount, this._fractionalBitCount); | ||
|
||
final int _integerBitCount; | ||
final int _fractionalBitCount; | ||
|
||
int get integer => _integerBitCount; | ||
int get fractional => _fractionalBitCount; | ||
} |
37 changes: 37 additions & 0 deletions
37
packages/ew_substrate_fixed/lib/src/parse_fixed_point.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import 'dart:math' as math; | ||
|
||
/// Parses a BigInt representing a fixed point number with the given | ||
/// number of integer and fractional bits. | ||
double parseFixedPoint( | ||
BigInt input, { | ||
required int integerBitCount, | ||
required int fractionalBitCount, | ||
}) { | ||
final len = integerBitCount + fractionalBitCount; | ||
final signed = input.toSigned(len); | ||
|
||
// we have to get rid of the `-` within the string. We prepend it later again | ||
// if necessary. | ||
final bits = signed.toRadixString(2).replaceFirst('-', '').padLeft(len, '0'); | ||
final fractionalBits = bits.substring(bits.length - fractionalBitCount); | ||
var integerBits = bits.substring(0, bits.length - fractionalBitCount); | ||
|
||
if (signed.isNegative) { | ||
integerBits = '-$integerBits'; | ||
} | ||
|
||
// print('bits: $bits'); | ||
// print('fractionalBits: $fractionalBits'); | ||
// print('integerBits: $integerBits'); | ||
|
||
final fractionalPart = fractionalBits | ||
.split('') | ||
.asMap() | ||
.entries | ||
.map((entry) => entry.value == '1' ? 1 / math.pow(2, entry.key + 1) : 0) | ||
.reduce((acc, val) => acc + val); | ||
|
||
final integerPart = integerBits.isNotEmpty ? int.parse(integerBits, radix: 2) : 0; | ||
|
||
return (integerPart + (signed.isNegative ? -fractionalPart : fractionalPart)).toDouble(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import 'package:ew_substrate_fixed/src/exception.dart'; | ||
|
||
/// Returns a BigInt representing a positive fixed point number with the given | ||
/// number of integer and fractional bits. | ||
/// | ||
/// Note: This doesn't work for negative numbers yet, but as the runtime uses | ||
/// unsigned types, we don't really need it anyhow. | ||
BigInt toFixedPoint( | ||
double input, { | ||
required int integerBitCount, | ||
required int fractionalBitCount, | ||
}) { | ||
if (input.isNegative) throw FixedPointException.unsupportedNegativeValues(); | ||
|
||
final integerBits = input.toInt(); | ||
final bits = integerBits.toRadixString(2) + getFractionalBits(input, fractionalBitCount); | ||
return BigInt.parse(bits, radix: 2); | ||
} | ||
|
||
/// Extract the fractional bits of a double number. | ||
String getFractionalBits(double number, int bitCount) { | ||
// Extract the fractional part of the double number | ||
var fractionalPart = number - number.toInt(); | ||
|
||
// Convert the fractional part to its binary representation | ||
var binaryFractionalPart = ''; | ||
while (fractionalPart > 0) { | ||
// Multiply the fractional part by 2 and add the bit to the binary representation | ||
fractionalPart *= 2; | ||
if (fractionalPart >= 1) { | ||
binaryFractionalPart += '1'; | ||
fractionalPart -= 1; | ||
} else { | ||
binaryFractionalPart += '0'; | ||
} | ||
} | ||
|
||
// Pads the `fractionalPart` if shorter than `bitCount`, and truncates it | ||
// if longer than `bigCount`. | ||
return binaryFractionalPart.padRight(bitCount, '0').substring(0, bitCount); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
library substrate_fixed; | ||
|
||
export 'src/fixed_point.dart' show U16F16, U32F32, U64F64; | ||
export 'src/fixed_point_util.dart' show u16F16Util, u32F32Util, u64F64Util; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
name: ew_substrate_fixed | ||
description: Implements fixed point handling in dart | ||
version: 0.0.1 | ||
publish_to: none | ||
|
||
environment: | ||
sdk: ">=3.0.3 <4.0.0" | ||
|
||
dev_dependencies: | ||
test: ^1.24.3 | ||
very_good_analysis: ^5.0.0+1 |
54 changes: 54 additions & 0 deletions
54
packages/ew_substrate_fixed/test/parse_fixed_point_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import 'package:ew_substrate_fixed/src/parse_fixed_point.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group('parseFixedPoint', () { | ||
test('parses 0 as U16F16', () { | ||
final zero = BigInt.from(0x0); | ||
final output = parseFixedPoint(zero, integerBitCount: 16, fractionalBitCount: 16); | ||
expect(output, 0); | ||
}); | ||
|
||
test('parses 0 as U64F64', () { | ||
final zero = BigInt.parse('00000000000000000000000000000000', radix: 16); | ||
final output = parseFixedPoint(zero, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, 0); | ||
}); | ||
|
||
test('parses -0 as U64F64', () { | ||
final zero = BigInt.parse('-0', radix: 16); | ||
final output = parseFixedPoint(zero, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, 0); | ||
}); | ||
|
||
test('parses 1 as U64F64', () { | ||
final one = BigInt.parse('18446744073709551616'); | ||
final output = parseFixedPoint(one, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, 1); | ||
}); | ||
|
||
test('parses 1 as U16F16', () { | ||
final one = BigInt.from(0x10000); | ||
final output = parseFixedPoint(one, integerBitCount: 16, fractionalBitCount: 16); | ||
expect(output, 1); | ||
}); | ||
|
||
test('parses 18.5435...', () { | ||
final input = BigInt.from(0x128b260000); | ||
final output = parseFixedPoint(input, integerBitCount: 32, fractionalBitCount: 32); | ||
expect(output, 18.543548583984375); | ||
}); | ||
|
||
test('parses -18.1234', () { | ||
final input = BigInt.parse('FFFFFFFFFFFFFFEDE068DB8BAC710000', radix: 16); | ||
final output = parseFixedPoint(input, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, -18.1234); | ||
}); | ||
|
||
test('parses 18.1234', () { | ||
final input = BigInt.parse('00000000000000121F972474538F0000', radix: 16); | ||
final output = parseFixedPoint(input, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, 18.1234); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import 'package:ew_substrate_fixed/src/exception.dart'; | ||
import 'package:ew_substrate_fixed/src/to_fixed_point.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group('toFixedPoint', () { | ||
test('1.0 to I16F16 works', () { | ||
const one = 1.0; | ||
final output = toFixedPoint(one, integerBitCount: 16, fractionalBitCount: 16); | ||
expect(output, BigInt.from(0x10000)); | ||
}); | ||
|
||
test('0.0 to I16F16 works', () { | ||
const zero = 0.0; | ||
final output = toFixedPoint(zero, integerBitCount: 16, fractionalBitCount: 16); | ||
expect(output, BigInt.from(0x0)); | ||
}); | ||
|
||
test('1.1 to I16F16 works', () { | ||
const input = 1.1; | ||
final output = toFixedPoint(input, integerBitCount: 16, fractionalBitCount: 16); | ||
expect(output, BigInt.from(0x011999)); | ||
}); | ||
|
||
test('18.4062... to I64F64 works', () { | ||
const one = 18.4062194824218714473; | ||
final output = toFixedPoint(one, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, BigInt.parse('1267fdffffffff0000', radix: 16)); | ||
}); | ||
|
||
test('18.1234 to I64F64 works', () { | ||
const input = 18.1234; | ||
final output = toFixedPoint(input, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, BigInt.parse('00000000000000121F972474538F0000', radix: 16)); | ||
}); | ||
|
||
test('returns 0 for small number', () { | ||
const input = 0.000000000000000000000000000000000000001; | ||
final output = toFixedPoint(input, integerBitCount: 64, fractionalBitCount: 64); | ||
expect(output, BigInt.from(0)); | ||
}); | ||
|
||
test('throws exception for negative values', () { | ||
expect( | ||
() => toFixedPoint(-1, integerBitCount: 64, fractionalBitCount: 64), | ||
throwsA(isA<FixedPointException>()), | ||
); | ||
}); | ||
}); | ||
} |