Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,8 @@
import org.apache.arrow.vector.file.json.JsonFileReader;
import org.apache.arrow.vector.file.json.JsonFileWriter;
import org.apache.arrow.vector.schema.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.ArrowType;
import org.apache.arrow.vector.types.pojo.ArrowType.FloatingPoint;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
import org.apache.commons.cli.CommandLine;
Expand DownExpand Up@@ -247,14 +249,61 @@ private static void compare(VectorSchemaRoot arrowRoot, VectorSchemaRoot jsonRoo
for (int j = 0; j < valueCount; j++) {
Object arrow = arrowVector.getAccessor().getObject(j);
Object json = jsonVector.getAccessor().getObject(j);
if (!Objects.equal(arrow, json)) {
if (!equals(field.getType(), arrow, json)) {
throw new IllegalArgumentException(
"Different values in column:\n" + field + " at index " + j + ": " + arrow + " != " + json);
}
}
}
}

private static boolean equals(ArrowType type, final Object arrow, final Object json) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposed functions in the jira. The code here is insufficient for a number of situations.

if (type instanceof ArrowType.FloatingPoint) {
FloatingPoint fpType = (FloatingPoint) type;
switch (fpType.getPrecision()) {
case DOUBLE:
return equalEnough((Double)arrow, (Double)json);
case SINGLE:
return equalEnough((Float)arrow, (Float)json);
case HALF:
default:
throw new UnsupportedOperationException("unsupported precision: " + fpType);
}
}
return Objects.equal(arrow, json);
}

static boolean equalEnough(Float f1, Float f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
float average = Math.abs((f1 + f2) / 2);
float differenceScaled = Math.abs(f1 - f2) / (average == 0.0f ? 1f : average);
return differenceScaled < 1.0E-6f;
}

static boolean equalEnough(Double f1, Double f2) {
if (f1 == null || f2 == null) {
return f1 == null && f2 == null;
}
if (f1.isNaN()) {
return f2.isNaN();
}
if (f1.isInfinite()) {
return f2.isInfinite() && Math.signum(f1) == Math.signum(f2);
}
double average = Math.abs((f1 + f2) / 2);
double differenceScaled = Math.abs(f1 - f2) / (average == 0.0d ? 1d : average);
return differenceScaled < 1.0E-12d;
}


private static void compareSchemas(Schema jsonSchema, Schema arrowSchema) {
if (!arrowSchema.equals(jsonSchema)) {
throw new IllegalArgumentException("Different schemas:\n" + arrowSchema + "\n" + jsonSchema);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,10 @@
import static org.apache.arrow.tools.ArrowFileTestFixtures.write;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeData;
import static org.apache.arrow.tools.ArrowFileTestFixtures.writeInput;
import static org.apache.arrow.tools.Integration.equalEnough;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
Expand All@@ -39,9 +43,9 @@
import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
import org.apache.arrow.vector.complex.writer.BigIntWriter;
import org.apache.arrow.vector.complex.writer.Float8Writer;
import org.apache.arrow.vector.complex.writer.IntWriter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand DownExpand Up@@ -121,7 +125,7 @@ public void testJSONRoundTripWithVariableWidth() throws Exception {
String i, o;
int j = 0;
while ((i = orig.readLine()) != null && (o = rt.readLine()) != null) {
Assert.assertEquals("line: " + j, i, o);
assertEquals("line: " + j, i, o);
++j;
}
}
Expand All@@ -142,6 +146,33 @@ private BufferedReader readNormalized(File f) throws IOException {
}


/**
* the test should not be sensitive to small variations in float representation
*/
@Test
public void testFloat() throws Exception {
File testValidInFile = testFolder.newFile("testValidFloatIn.arrow");
File testInvalidInFile = testFolder.newFile("testAlsoValidFloatIn.arrow");
File testJSONFile = testFolder.newFile("testValidOut.json");
testJSONFile.delete();

// generate an arrow file
writeInputFloat(testValidInFile, allocator, 912.4140000000002, 912.414);
// generate a different arrow file
writeInputFloat(testInvalidInFile, allocator, 912.414, 912.4140000000002);

Integration integration = new Integration();

// convert the "valid" file to json
String[] args1 = { "-arrow", testValidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.ARROW_TO_JSON.name()};
integration.run(args1);

// compare the "invalid" file to the "valid" json
String[] args3 = { "-arrow", testInvalidInFile.getAbsolutePath(), "-json", testJSONFile.getAbsolutePath(), "-command", Command.VALIDATE.name()};
// this should fail
integration.run(args3);
}

@Test
public void testInvalid() throws Exception {
File testValidInFile = testFolder.newFile("testValidIn.arrow");
Expand All@@ -167,12 +198,28 @@ public void testInvalid() throws Exception {
integration.run(args3);
fail("should have failed");
} catch (IllegalArgumentException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
Assert.assertTrue(e.getMessage(), e.getMessage().contains("999"));
assertTrue(e.getMessage(), e.getMessage().contains("Different values in column"));
assertTrue(e.getMessage(), e.getMessage().contains("999"));
}

}

static void writeInputFloat(File testInFile, BufferAllocator allocator, double... f) throws FileNotFoundException, IOException {
try (
BufferAllocator vectorAllocator = allocator.newChildAllocator("original vectors", 0, Integer.MAX_VALUE);
MapVector parent = new MapVector("parent", vectorAllocator, null)) {
ComplexWriter writer = new ComplexWriterImpl("root", parent);
MapWriter rootWriter = writer.rootAsMap();
Float8Writer floatWriter = rootWriter.float8("float");
for (int i = 0; i < f.length; i++) {
floatWriter.setPosition(i);
floatWriter.writeFloat8(f[i]);
}
writer.setValueCount(f.length);
write(parent.getChild("root"), testInFile);
}
}

static void writeInput2(File testInFile, BufferAllocator allocator) throws FileNotFoundException, IOException {
int count = ArrowFileTestFixtures.COUNT;
try (
Expand All@@ -192,4 +239,33 @@ static void writeInput2(File testInFile, BufferAllocator allocator) throws FileN
}
}

@Test
public void testFloatComp() {
assertTrue(equalEnough(912.4140000000002F, 912.414F));
assertTrue(equalEnough(912.4140000000002D, 912.414D));
assertTrue(equalEnough(912.414F, 912.4140000000002F));
assertTrue(equalEnough(912.414D, 912.4140000000002D));
assertFalse(equalEnough(912.414D, 912.4140001D));
assertFalse(equalEnough(null, 912.414D));
assertTrue(equalEnough((Float)null, null));
assertTrue(equalEnough((Double)null, null));
assertFalse(equalEnough(912.414D, null));
assertFalse(equalEnough(Double.MAX_VALUE, Double.MIN_VALUE));
assertFalse(equalEnough(Double.MIN_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MAX_VALUE, Double.MAX_VALUE));
assertTrue(equalEnough(Double.MIN_VALUE, Double.MIN_VALUE));
assertTrue(equalEnough(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
assertFalse(equalEnough(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
assertTrue(equalEnough(Double.NaN, Double.NaN));
assertFalse(equalEnough(1.0, Double.NaN));
assertFalse(equalEnough(Float.MAX_VALUE, Float.MIN_VALUE));
assertFalse(equalEnough(Float.MIN_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MAX_VALUE, Float.MAX_VALUE));
assertTrue(equalEnough(Float.MIN_VALUE, Float.MIN_VALUE));
assertTrue(equalEnough(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
assertFalse(equalEnough(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
assertTrue(equalEnough(Float.NaN, Float.NaN));
assertFalse(equalEnough(1.0F, Float.NaN));
}

}