Skip to content

Commit

Permalink
Add tool floating-point-number-converter.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rapha149 committed Oct 16, 2024
1 parent f962c41 commit 374c15e
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 0 deletions.
1 change: 1 addition & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ declare module '@vue/runtime-core' {
Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']
EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
FloatingPointNumberConverter: typeof import('./src/tools/floating-point-number-converter/floating-point-number-converter.vue')['default']
FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
GitMemo: typeof import('./src/tools/git-memo/git-memo.vue')['default']
'GitMemo.content': typeof import('./src/tools/git-memo/git-memo.content.md')['default']
Expand Down
4 changes: 4 additions & 0 deletions locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,10 @@ tools:
description: >-
Konvertiere Zahlen zwischen verschiedenen Basen (Dezimal, Hexadezimal,
Binär, Oktal, Base64, ...).
floating-point-converter:
title: Konverter für Fließkommazahlen
description: >-
Konvertiere eine Dezimalzahl in eine IEEE-754 binäre Fließkommazahl oder umgekehrt.
yaml-to-json-converter:
title: YAML zu JSON
description: Konvertiere YAML einfach in JSON mit diesem Live-Online-Konverter.
Expand Down
4 changes: 4 additions & 0 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ tools:
title: Integer base converter
description: Convert a number between different bases (decimal, hexadecimal, binary, octal, base64, ...)

floating-point-converter:
title: Floating point number converter
description: Convert a decimal number to a IEEE 754 binary floating point number or vice versa.

yaml-to-json-converter:
title: YAML to JSON converter
description: Simply convert YAML to JSON with this online live converter.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { expect, describe, it } from 'vitest';

Check failure on line 1 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Member 'describe' of the import declaration should be sorted alphabetically
import { convertDecimalToBinary } from './floating-point-number-converter.model';

Check warning on line 2 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

'/home/runner/work/it-tools/it-tools/src/tools/floating-point-number-converter/floating-point-number-converter.model.ts' imported multiple times
import { convertBinaryToDecimal } from './floating-point-number-converter.model';

Check warning on line 3 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

'/home/runner/work/it-tools/it-tools/src/tools/floating-point-number-converter/floating-point-number-converter.model.ts' imported multiple times

describe('floating-point-number-converter', () => {
describe('convertDecimalToBinary', () => {
it('Should convert a decimal number to a floating point binary number (IEEE-754)', () => {
// 32-Bit

Check failure on line 8 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '0', bitCount: 32 })).toEqual('00000000000000000000000000000000');

Check failure on line 9 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '-0', bitCount: 32 })).toEqual('10000000000000000000000000000000');

Check failure on line 10 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: 'NaN', bitCount: 32 })).toEqual('01111111110000000000000000000000');

Check failure on line 11 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: 'Infinity', bitCount: 32 })).toEqual('01111111100000000000000000000000');

Check failure on line 12 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '-Infinity', bitCount: 32 })).toEqual('11111111100000000000000000000000');

Check failure on line 13 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '2.5', bitCount: 32 })).toEqual('01000000001000000000000000000000');

Check failure on line 14 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '-128.25', bitCount: 32 })).toEqual('11000011000000000100000000000000');

Check failure on line 15 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '0.1', bitCount: 32 })).toEqual('00111101110011001100110011001101');

Check failure on line 16 in src/tools/floating-point-number-converter/floating-point-number-converter.model.test.ts

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8
expect(convertDecimalToBinary({ value: '3.4028235e38', bitCount: 32 })).toEqual('01111111011111111111111111111111');
expect(convertDecimalToBinary({ value: '1.1754942e-38', bitCount: 32 })).toEqual('00000000011111111111111111111111');

// 64-Bit
expect(convertDecimalToBinary({ value: '0', bitCount: 64 })).toEqual('0000000000000000000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: '-0', bitCount: 64 })).toEqual('1000000000000000000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: 'NaN', bitCount: 64 })).toEqual('0111111111111000000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: 'Infinity', bitCount: 64 })).toEqual('0111111111110000000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: '-Infinity', bitCount: 64 })).toEqual('1111111111110000000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: '2.5', bitCount: 64 })).toEqual('0100000000000100000000000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: '-128.25', bitCount: 64 })).toEqual('1100000001100000000010000000000000000000000000000000000000000000');
expect(convertDecimalToBinary({ value: '0.1', bitCount: 64 })).toEqual('0011111110111001100110011001100110011001100110011001100110011010');
expect(convertDecimalToBinary({ value: '1.7976931348623157e308', bitCount: 64 })).toEqual('0111111111101111111111111111111111111111111111111111111111111111');
expect(convertDecimalToBinary({ value: '2.225073858507201e-308', bitCount: 64 })).toEqual('0000000000001111111111111111111111111111111111111111111111111111');
});
});
describe('convertBinaryToDecimal', () => {
it('Should convert a floating point binary number (IEEE-754) to a decimal number', () => {
// 32-Bit
expect(convertBinaryToDecimal({ value: '00000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '10000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '01111111110000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '11111111110000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '01111111110000000000000000000001', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '01111111100000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('Infinity');
expect(convertBinaryToDecimal({ value: '11111111100000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-Infinity');
expect(convertBinaryToDecimal({ value: '01000000001000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('2.5' + '0'.repeat(31));
expect(convertBinaryToDecimal({ value: '01000000001000000000000000000000', decimalPrecision: '32', removeZeroPadding: true })).toEqual('2.5');
expect(convertBinaryToDecimal({ value: '11000011000000000100000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-128.25' + '0'.repeat(30));
expect(convertBinaryToDecimal({ value: '00111101110011001100110011001101', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.10000000149011611938476562500000');
expect(convertBinaryToDecimal({ value: '00111101110011001100110011001101', decimalPrecision: '10', removeZeroPadding: false })).toEqual('0.1000000015');
expect(convertBinaryToDecimal({ value: '00111101110011001100110011001101', decimalPrecision: '1', removeZeroPadding: false })).toEqual('0.1');
expect(convertBinaryToDecimal({ value: '01111111011111111111111111111111', decimalPrecision: '32', removeZeroPadding: false })).matches(/^3\.402823\d*e\+?38$/);
expect(convertBinaryToDecimal({ value: '00000000011111111111111111111111', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '00000000011111111111111111111111', decimalPrecision: '64', removeZeroPadding: false })).toEqual('0.0000000000000000000000000000000000000117549421069244107548702944');
expect(convertBinaryToDecimal({ value: '00000000011111111111111111111111', decimalPrecision: '', removeZeroPadding: false })).matches(/^1\.1754942\d*e-38$/);

// 64-Bit
expect(convertBinaryToDecimal({ value: '0000000000000000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '1000000000000000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '0111111111111000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '1111111111111000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '0111111111111000000000000000000000000000000000000000000000000001', decimalPrecision: '32', removeZeroPadding: false })).toEqual('NaN');
expect(convertBinaryToDecimal({ value: '0111111111110000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('Infinity');
expect(convertBinaryToDecimal({ value: '1111111111110000000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-Infinity');
expect(convertBinaryToDecimal({ value: '0100000000000100000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('2.5' + '0'.repeat(31));
expect(convertBinaryToDecimal({ value: '0100000000000100000000000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: true })).toEqual('2.5');
expect(convertBinaryToDecimal({ value: '1100000001100000000010000000000000000000000000000000000000000000', decimalPrecision: '32', removeZeroPadding: false })).toEqual('-128.25' + '0'.repeat(30));
expect(convertBinaryToDecimal({ value: '0011111110111001100110011001100110011001100110011001100110011010', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.10000000000000000555111512312578');
expect(convertBinaryToDecimal({ value: '0011111110111001100110011001100110011001100110011001100110011010', decimalPrecision: '10', removeZeroPadding: false })).toEqual('0.1000000000');
expect(convertBinaryToDecimal({ value: '0011111110111001100110011001100110011001100110011001100110011010', decimalPrecision: '1', removeZeroPadding: false })).toEqual('0.1');
expect(convertBinaryToDecimal({ value: '0111111111101111111111111111111111111111111111111111111111111111', decimalPrecision: '32', removeZeroPadding: false })).matches(/^1\.79769313\d*e\+?308$/);
expect(convertBinaryToDecimal({ value: '0000000000001111111111111111111111111111111111111111111111111111', decimalPrecision: '32', removeZeroPadding: false })).toEqual('0.' + '0'.repeat(32));
expect(convertBinaryToDecimal({ value: '0000000000001111111111111111111111111111111111111111111111111111', decimalPrecision: '100', removeZeroPadding: false })).toEqual('0.' + '0'.repeat(100));
expect(convertBinaryToDecimal({ value: '0000000000001111111111111111111111111111111111111111111111111111', decimalPrecision: '', removeZeroPadding: false })).matches(/^2\.2250738585\d*e-308$/);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export function convertDecimalToBinary({ value, bitCount }: { value: string; bitCount: number }) {
let number = parseFloat(value.replace(/\s/g,''));
if (value.match(/^-?inf(inity)?$/i)) {
// const sign = value.startsWith('-') ? 1 : 0;
// return `${sign}${'1'.repeat(exponentBits)}${'0'.repeat(mantissaBits)}`;
number = (value.startsWith('-') ? -2 : 2) / 0;
}

switch (bitCount) {
case 32: // Single precision
var uint = new Uint32Array(Float32Array.of(number).buffer);
return uint[0].toString(2).padStart(32, '0');
case 64: // Double precision
var uint = new Uint32Array(Float64Array.of(number).buffer);
return [...uint].slice(0, 2).reverse().map(p => p.toString(2).padStart(32, '0')).join('');
default:
throw new Error("Unsupported bit count. Only 32 and 64 are allowed.");
}
}

export function convertBinaryToDecimal({ value, decimalPrecision, removeZeroPadding }: { value: string, decimalPrecision: string, removeZeroPadding: boolean }) {
if (value.match(/[^01]/))
throw new Error("Not a binary number.");
if (decimalPrecision.match(/[^\d]/))
throw new Error("Decimal Precision must be a positive whole number.");

let result: number;
switch (value.length) {
case 32:
var binary = [parseInt(value, 2)];
result = (new Float32Array(Uint32Array.from(binary).buffer))[0];
break;
case 64:
var binary = [parseInt(value.substring(32), 2), parseInt(value.substring(0, 32), 2)];
result = (new Float64Array(Uint32Array.from(binary).buffer))[0];
break;
default:
throw new Error("Invalid length. Supply a binary string with length 32 or 64.");
}

let zeroNegative = result == 0 && 2 / result == -Infinity;
let resultString = decimalPrecision.length == 0 ? result.toString() : result.toFixed(parseInt(decimalPrecision));
if (removeZeroPadding)
resultString = resultString.replace(/\.(\d+?)(0+)$/, '.$1');
return (zeroNegative ? '-' : '') + resultString;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<script setup lang="ts">
import InputCopyable from '../../components/InputCopyable.vue';
import { convertDecimalToBinary } from './floating-point-number-converter.model';

Check warning on line 3 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

'/home/runner/work/it-tools/it-tools/src/tools/floating-point-number-converter/floating-point-number-converter.model.ts' imported multiple times
import { convertBinaryToDecimal } from './floating-point-number-converter.model';

Check warning on line 4 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

'/home/runner/work/it-tools/it-tools/src/tools/floating-point-number-converter/floating-point-number-converter.model.ts' imported multiple times
import { convertBase } from '../integer-base-converter/integer-base-converter.model';
import { getErrorMessageIfThrows } from '@/utils/error';
const bitCount = ref(32);
const decimalInput = ref('42.42');
const binaryOutput = ref();
const actualValue = ref();
const binaryInput = ref('01000010001010011010111000010100');
const decimalPrecision = ref('32');
const showTrailingZeros = ref(false);
function errorlessBinaryToDecimalConversion(...args: Parameters<typeof convertBinaryToDecimal>) {
try {
return convertBinaryToDecimal(...args);
}
catch (err) {
return '';
}
}
const binaryToDecimalError = computed(() =>
getErrorMessageIfThrows(() =>
convertBinaryToDecimal({ value: binaryInput.value, decimalPrecision: decimalPrecision.value, removeZeroPadding: false }),
),
);
</script>

<template>
<c-card title="Decimal to Binary" style="min-width: 650px">
<c-input-text
v-model:value="decimalInput"

Check warning on line 37 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
label="Decimal Number"

Check warning on line 38 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
placeholder="Put your decimal number here (ex: 42.42)"

Check warning on line 39 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
label-position="left"

Check warning on line 40 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
label-width="210px"

Check warning on line 41 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
label-align="right"

Check warning on line 42 in src/tools/floating-point-number-converter/floating-point-number-converter.vue

View workflow job for this annotation

GitHub Actions / ci

Expected indentation of 6 spaces but found 8 spaces
mb-2
/>

<c-select
v-model:value="bitCount"
mb-4
label="Bit Count"
label-position="left"
label-width="210px"
label-align="right"
:options="[
{
label: '32-Bit (Single precision)',
value: 32,
},
{
label: '64-Bit (Double precision)',
value: 64,
},
]"
/>

<n-divider />

<InputCopyable
label="Binary Number"
placeholder="Binary Number"
:value="binaryOutput = convertDecimalToBinary({ value: decimalInput, bitCount: bitCount })"
readonly
label-position="left"
label-width="210px"
label-align="right"
mb-2
/>

<InputCopyable
label="Hexadecimal Representation"
placeholder="Hexadecimal Representation"
:value="convertBase({ value: binaryOutput, fromBase: 2, toBase: 16 })"
readonly
label-position="left"
label-width="210px"
label-align="right"
mb-2
/>

<InputCopyable
label="Actually stored value"
placeholder="Actually stored value"
:value="actualValue = errorlessBinaryToDecimalConversion({ value: binaryOutput, decimalPrecision: '32', removeZeroPadding: true })"
readonly
label-position="left"
label-width="210px"
label-align="right"
mb-2
/>

<InputCopyable
label="Error due to conversion"
placeholder="Error due to conversion"
:value="(decimalInput - actualValue).toFixed(32).replace(/\.(\d+?)(0+)$/, '.$1')"
readonly
label-position="left"
label-width="210px"
label-align="right"
mb-2
/>
</c-card>

<c-card title="Binary to Decimal" style="min-width: 650px">
<c-input-text
v-model:value="binaryInput"
label="Binary Number"
placeholder="Put your binary number here (ex: 01000010001010011010111000010100)"
label-position="left"
label-width="140px"
label-align="right"
mb-2
/>

<c-input-text
v-model:value="decimalPrecision"
label="Decimal Precision"
placeholder="Choose the decimal precision (digits after the decimal point)."
label-position="left"
label-width="140px"
label-align="right"
mb-2
/>

<n-form-item
label="Show Trailing Zeros"
label-placement="left"
label-width="140px"
label-align="right">
<n-switch v-model:value="showTrailingZeros" />
</n-form-item>

<n-alert v-if="binaryToDecimalError" style="margin-top: 25px" type="error">
{{ binaryToDecimalError }}
</n-alert>

<n-divider />

<InputCopyable
label="Decimal Number"
placeholder="Decimal Number"
:value="errorlessBinaryToDecimalConversion({ value: binaryInput, decimalPrecision: decimalPrecision, removeZeroPadding: !showTrailingZeros })"
readonly
label-position="left"
label-width="140px"
label-align="right"
mb-2
/>
</c-card>
</template>
13 changes: 13 additions & 0 deletions src/tools/floating-point-number-converter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ArrowsLeftRight } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';

export const tool = defineTool({
name: translate('tools.floating-point-converter.title'),
path: '/floating-point-converter',
description: translate('tools.floating-point-converter.description'),
keywords: ['converter', 'floating', 'point', 'number', 'converter', 'binary', 'decimal'],
component: () => import('./floating-point-number-converter.vue'),
icon: ArrowsLeftRight,
createdAt: new Date('2024-10-12'),
});
2 changes: 2 additions & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as floatingPointNumberConverter } from './floating-point-number-converter';
import { tool as emailNormalizer } from './email-normalizer';

import { tool as asciiTextDrawer } from './ascii-text-drawer';
Expand Down Expand Up @@ -98,6 +99,7 @@ export const toolsByCategory: ToolCategory[] = [
components: [
dateTimeConverter,
baseConverter,
floatingPointNumberConverter,
romanNumeralConverter,
base64StringConverter,
base64FileConverter,
Expand Down

0 comments on commit 374c15e

Please sign in to comment.